atl_subresolution_module.f90 Source File


This file depends on

sourcefile~~atl_subresolution_module.f90~~EfferentGraph sourcefile~atl_subresolution_module.f90 atl_subresolution_module.f90 sourcefile~ply_dof_module.f90 ply_dof_module.f90 sourcefile~atl_subresolution_module.f90->sourcefile~ply_dof_module.f90

Source Code

! Copyright (c) 2016-2018 Peter Vitt <peter.vitt2@uni-siegen.de>
! Copyright (c) 2016 Tobias Girresser <tobias.girresser@student.uni-siegen.de>
! Copyright (c) 2017 Daniel PetrĂ³ <daniel.petro@student.uni-siegen.de>
!
! Permission to use, copy, modify, and distribute this software for any
! purpose with or without fee is hereby granted, provided that the above
! copyright notice and this permission notice appear in all copies.
!
! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! **************************************************************************** !

! Copyright (c) 2014,2016-2017 Peter Vitt <peter.vitt2@uni-siegen.de>
! Copyright (c) 2014 Harald Klimach <harald.klimach@uni-siegen.de>
!
! Parts of this file were written by Peter Vitt and Harald Klimach for
! University of Siegen.
!
! Permission to use, copy, modify, and distribute this software for any
! purpose with or without fee is hereby granted, provided that the above
! copyright notice and this permission notice appear in all copies.
!
! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! **************************************************************************** !
!
! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for Q-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * Ansatzfunction index in y direction. Index starts with 1.
! * Ansatzfunction index in z direction. Index starts with 1.
! * The maximal polynomial degree per spatial direction.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for Q-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * Ansatzfunction index in y direction. Index starts with 1.
! * The maximal polynomial degree per spatial direction.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for Q-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for P-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * Ansatzfunction index in y direction. Index starts with 1.
! * Ansatzfunction index in z direction. Index starts with 1.
! * The maximal polynomial degree per spatial direction.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for P-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * Ansatzfunction index in y direction. Index starts with 1.
! * The maximal polynomial degree per spatial direction.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for P-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the number of degrees of freedom for Q polynomial space
! Your must provide:
! * The maximal polynomial degree per spatial direction
! * The variable to store the number of degrees of freedom for a Q tensor
!   product polynomial


! Return the number of degrees of freedom for broken polynomial space
! Your must provide:
! * The maximal polynomial degree per spatial direction (for P Tensor product
!   polynomials this assumed to be the same for each spatial direction).
! * The variable to store the number of degrees of freedom for a P tensor
!   product polynomial


! Return the number of degrees of freedom for Q polynomial space
! You must provide:
! * The maximal polynomial degree per spatial direction
! * The variable to store the number of degrees of freedom for a Q tensor
!   product polynomial


! Return the number of degrees of freedom for broken polynomial space
! You must provide:
! * The maximal polynomial degree per spatial direction (for P Tensor product
!   polynomials this assumed to be the same for each spatial direction).
! * A variable to store the number of degrees of freedom for a P tensor product
!   polynomial


! Return the number of degrees of freedom for Q polynomial space
! You must provide:
! * The maximal polynomial degree per spatial direction
! * The variable to store the number of degrees of freedom for a Q tensor
!   product polynomial


! Return the number of degrees of freedom for broken polynomial space
! You must provide:
! * The maximal polynomial degree per spatial direction (for P Tensor product
!   polynomials this assumed to be the same for each spatial direction).
! * The variable to store the number of degrees of freedom for a P tensor
!   product polynomial

! The x, y and z ansatz degrees are turned into the degrees of the next
! ansatz function in the layered P list
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
! * Ansatz function index in y direction. First ansatz function has index 1.
! * Ansatz function index in z direction. First ansatz function has index 1.

! The x and y ansatz degrees are turned into the degrees of the next
! ansatz function in the layered P list
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
! * Ansatz function index in y direction. First ansatz function has index 1.

! The x ansatz degree is turned into the degree of the next
! ansatz function in the layered P list
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.

! The x, y and z ansatz degrees are turned into the degrees of the next
! ansatz function in the linearized Q tensor
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
! * Ansatz function index in y direction. First ansatz function has index 1.
! * Ansatz function index in z direction. First ansatz function has index 1.
! * Maximal polynomial degree

! The x and y ansatz degrees are turned into the degrees of the next
! ansatz function in the linearized Q tensor
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
! * Ansatz function index in y direction. First ansatz function has index 1.
! * Maximal polynomial degree

! The x ansatz degree is turned into the degree of the next
! ansatz function in the linearized Q tensor
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
module atl_subresolution_module
  use env_module, only: pathLen, rk, isLittleEndian, long_k, newunit

  use aotus_module, only: flu_State, aot_get_val, aoterr_Fatal, close_config

  use treelmesh_module,       only: treelmesh_type
  use tem_aux_module,         only: tem_open_distconf, tem_abort
  use tem_color_prop_module,  only: tem_color_prop_type
  use tem_comm_env_module,    only: tem_comm_env_type
  use tem_logging_module,     only: logunit
  use tem_subres_prop_module, only: tem_subres_prop_type, tem_subres_prop_load
  use tem_tools_module,       only: upper_to_lower

  use ply_dof_module, only: P_Space, Q_space

  implicit none

  private

  type atl_subresolution_type
    integer :: polydegree
    integer :: basisType
    type(tem_subres_prop_type) :: subres_prop
  end type atl_subresolution_type

  public :: atl_subresolution_type, atl_subresolution_load
  public :: atl_subres_import_color


contains


  ! ****************************************************************************!
  !> Subroutine to load subresolution information for a given tree.
  subroutine atl_subresolution_load(me, tree, proc, coloring)
    ! --------------------------------------------------------------------------!
    type(atl_subresolution_type), intent(out) :: me
    type(treelmesh_type), intent(in) :: tree
    type(tem_comm_env_type), intent(in) :: proc
    type(tem_color_prop_type), intent(in) :: coloring
    ! --------------------------------------------------------------------------!
    character(len=pathLen) :: configfile
    character :: polyspace
    type(flu_State) :: conf
    integer :: iError
    ! --------------------------------------------------------------------------!

    configfile = trim(tree%global%dirname)//'subresolution.lua'

    call tem_subres_prop_load( me       = me%subres_prop, &
      &                        tree     = tree,           &
      &                        coloring = coloring        )

    call tem_open_distconf( L        = conf,             &
      &                     filename = trim(configfile), &
      &                     proc     = proc              )

    call aot_get_val( L       = conf,          &
      &               key     = 'polydegree',  &
      &               val     = me%polydegree, &
      &               ErrCode = iError         )

    if (btest(iError, aoterr_Fatal)) then
      write(logUnit(1),*) &
        &  'FATAL Error occured, while retrieving subresolution polydegree'
      call tem_abort()
    end if

    call aot_get_val( L       = conf,        &
      &               key     = 'polyspace', &
      &               val     = polyspace,   &
      &               default = 'q',         &
      &               ErrCode = iError       )

    polyspace = upper_to_lower(polyspace)
    select case(polyspace)
    case('q')
      me%basisType = Q_space

    case('p')
      me%basisType = P_space

    case default
      write(logunit(1),*) 'ERROR in subresolution loading!'
      write(logunit(1),*) 'Unknown polyspace ', trim(polyspace)
      write(logUnit(1),*) 'Supported are:'
      write(logUnit(1),*) '* Q (quadratic with i,j,k <= maxDegree)'
      write(logUnit(1),*) '* P (with i+j+k <= maxDegree)'
      write(logUnit(1),*) 'Stopping....'
      call tem_abort()

    end select

    call close_config(conf)

  end subroutine atl_subresolution_load
  ! ****************************************************************************!


  ! ****************************************************************************!
  !> Get the subresolution data for all elements for a given color and in the
  !! requested format.
  subroutine atl_subres_import_color( me, tree, coloring, iColor,              &
    &                                 target_degree, target_space, target_dim, &
    &                                 subresdat )
    ! --------------------------------------------------------------------------!
    type(atl_subresolution_type), intent(in) :: me
    type(treelmesh_type), intent(in) :: tree
    type(tem_color_prop_type), intent(in) :: coloring
    integer, intent(in) :: iColor
    integer, intent(in) :: target_degree
    integer, intent(in) :: target_space
    integer, intent(in) :: target_dim
    real(kind=rk), allocatable, intent(out) :: subresdat(:,:)
    ! --------------------------------------------------------------------------!
    character(len=pathLen) :: datfile
    integer :: target_Dofs
    integer :: in_dofs
    integer :: min_dofs
    integer :: pdim
    real(kind=rk), allocatable :: indat(:)
    character(len=4) :: datext
    integer :: rl
    integer :: fUnit
    integer :: nElems
    integer(kind=long_k) :: offset
    integer :: iElem
    integer :: iStep, iDof
    integer :: tt_X, tt_Y, tt_Z
    integer :: in_X, in_Y, in_Z
    integer :: tt_pos, in_pos
    integer :: tt_off, tt_zoff
    integer :: in_off, in_zoff
    integer :: minOrd
    ! --------------------------------------------------------------------------!


    ! Only need to do anything, if there is actually a subresolution property.
    ! Checking this via the association status of the property header.
    if (associated(me%subres_prop%header)) then

      if (isLittleEndian) then
        datext = '.lsb'
      else
        datext = '.msb'
      end if

      nElems = me%subres_prop%nElems(iColor)
      offset = me%subres_prop%offset(iColor)

      ! Figure out the target polynomial representation.
      select case(target_space)
      case (Q_Space)
        target_dofs = (target_degree+1)**target_dim

      case (P_Space)
        target_dofs = target_degree+1
        do pdim=2,target_dim
          target_dofs = (target_dofs * (target_degree+pdim) ) / pdim
        end do

      end select

      ! Figure out input polynomial representation.
      select case(me%basistype)
      case (Q_Space)
        in_dofs = (me%polydegree+1)**3

      case (P_Space)
        in_dofs = me%polydegree+1
        do pdim=2,3
          in_dofs = (in_dofs * (me%polydegree+pdim) ) / pdim
        end do

      end select

      ! Allocate arrays accordingly.
      allocate(indat(in_dofs))
      allocate(subresdat(target_dofs, nElems))

      inquire(iolength=rl) indat

      datfile = trim(tree%global%dirname) // 'subresdata_' &
        &       // trim(coloring%color_label(iColor)) // datext

      fUnit = newunit()

      open( unit = fUnit, file = datfile, action = 'read', &
        &   access = 'direct', form = 'unformatted',       &
        &   recl = rl, status = 'old'                      )

      minord = min(target_degree+1, me%polydegree+1)

      subresdat = 0.0_rk

      do iElem=1,nElems

        read(fUnit, rec=offset+iElem) indat

        select case(target_space)
        case (Q_Space)
          if (me%basistype == Q_Space) then
            ! Both, target and input are Q Polynomials
            select case(target_dim)
            case (1)
              subresdat(:minord, iElem) = indat(:minord)

            case (2)
              do tt_Y=0,minord-1
                tt_off = tt_Y*(target_degree+1)
                in_off = tt_Y*(me%polydegree+1)
                subresdat(tt_off+1:tt_off+minord, iElem) &
                  &  = indat(in_off+1:in_off+minord)
              end do

            case (3)
              do tt_Z=0,minord-1
                tt_zoff = tt_Z*(target_degree+1)**2
                in_zoff = tt_Z*(me%polydegree+1)**2
                do tt_Y=0,minord-1
                  tt_off = tt_Y*(target_degree+1) + tt_zoff
                  in_off = tt_Y*(me%polydegree+1) + in_zoff
                  subresdat(tt_off+1:tt_off+minord, iElem) &
                    &  = indat(in_off+1:in_off+minord)
                end do
              end do
            end select

          else

            ! Target is Q, but input is P
            select case(target_dim)
            case (1)
              subresdat(:minord, iElem) = indat(:minord)

            case (2)
              in_X = 1
              in_Y = 1
              do iDof=1,in_dofs
  ! integer divisions are no mistake here.
  in_pos = ((((in_x - 1) + (in_y - 1))            &
    &   * (((in_x - 1) + (in_y - 1)) + 1)) / 2 + 1) &
    & + (in_y - 1)
                tt_pos = in_X + (target_degree+1)*(in_Y-1)
                subresdat(tt_pos, iElem) = indat(in_pos)
                ! Ensure, that next iteration is in the target range
                do istep=iDof,in_dofs
  ! - ansatz indices are arranged in layers. within each layer, the total
  !   degree remains constant.
  ! - within each layer, we have blocks. within a block, ansfuncz is
  !   constant, y counts up and x accordingly down.
  ! - within each block, we have items. each item represents one particular
  !   combination of ansfuncx, -y, and -z degrees.
  if (in_x .ne. 1) then
    ! next item
    in_x = in_x - 1
    in_y = in_y + 1
  else
    ! next layer
    in_x = in_y + 1
    in_y = 1
  end if
                  if ((in_X <= minord) .and. (in_Y <= minord)) EXIT
                end do
                if ((in_X > minord) .or. (in_Y > minord)) EXIT
              end do

            case (3)
              in_X = 1
              in_Y = 1
              in_Z = 1
              do iDof=1,in_dofs
  ! integer divisions are no mistake here.
  in_pos = (((in_x + in_y + in_z - 3) &
    &     * (in_x + in_y + in_z - 2) &
    &     * (in_x + in_y + in_z - 1)) &
    &   / 6 + 1)             &
    & + ((in_z-1) * (in_x + in_y + in_z -2) &
    &   - ((in_z-2) * (in_z-1)) / 2) &
    & + (in_y-1)
                tt_pos = in_X + (target_degree+1)*( (in_Y-1) &
                  &                                + (target_degree+1)*(in_Z-1))
                subresdat(tt_pos, iElem) = indat(in_pos)
                ! Ensure, that next iteration is in the target range
                do istep=iDof,in_dofs
  ! - ansatz indices are arranged in layers. within each layer, the total
  !   degree remains constant.
  ! - within each layer, we have blocks. within a block, ansfuncz is
  !   constant, y counts up and x accordingly down.
  ! - within each block, we have items. each item represents one particular
  !   combination of ansfuncx, -y, and -z degrees.

  if (in_x .ne. 1) then
    ! next item
    in_x = in_x - 1
    in_y = in_y + 1
  elseif (in_y .ne. 1) then
    ! next block
    in_x = in_y - 1
    in_y = 1
    in_z = in_z + 1
  else
    ! next layer
    in_x = in_z + 1
    in_y = 1
    in_z = 1
  end if
                  if ( (in_X <= minord) .and. (in_Y <= minord) &
                    &                   .and. (in_Z <= minord) ) EXIT
                end do
                if ( (in_X > minord) .or. (in_Y > minord) &
                  &                  .or. (in_Z > minord) ) EXIT
              end do
            end select
          end if

        case (P_Space)
          if (me%basistype == Q_Space) then
            ! Target is P, input is Q
            select case(target_dim)
            case (1)
              subresdat(:minord, iElem) = indat(:minord)

            case (2)
              tt_X = 1
              tt_Y = 1
              do iDof=1,target_dofs
  ! integer divisions are no mistake here.
  tt_pos = ((((tt_x - 1) + (tt_y - 1))            &
    &   * (((tt_x - 1) + (tt_y - 1)) + 1)) / 2 + 1) &
    & + (tt_y - 1)
                in_pos = tt_X + (me%polydegree+1)*(tt_Y-1)
                subresdat(tt_pos, iElem) = indat(in_pos)
                ! Ensure, that next iteration is in the target range
                do istep=iDof,target_dofs
  ! - ansatz indices are arranged in layers. within each layer, the total
  !   degree remains constant.
  ! - within each layer, we have blocks. within a block, ansfuncz is
  !   constant, y counts up and x accordingly down.
  ! - within each block, we have items. each item represents one particular
  !   combination of ansfuncx, -y, and -z degrees.
  if (tt_x .ne. 1) then
    ! next item
    tt_x = tt_x - 1
    tt_y = tt_y + 1
  else
    ! next layer
    tt_x = tt_y + 1
    tt_y = 1
  end if
                  if ((tt_X <= minord) .and. (tt_Y <= minord)) EXIT
                end do
                if ((tt_X > minord) .or. (tt_Y > minord)) EXIT
              end do

            case (3)
              tt_X = 1
              tt_Y = 1
              tt_Z = 1
              do iDof=1,target_dofs
  ! integer divisions are no mistake here.
  tt_pos = (((tt_x + tt_y + tt_z - 3) &
    &     * (tt_x + tt_y + tt_z - 2) &
    &     * (tt_x + tt_y + tt_z - 1)) &
    &   / 6 + 1)             &
    & + ((tt_z-1) * (tt_x + tt_y + tt_z -2) &
    &   - ((tt_z-2) * (tt_z-1)) / 2) &
    & + (tt_y-1)
                in_pos = tt_X + (me%polydegree+1)*( (tt_Y-1) &
                  &                                + (me%polydegree+1)*(tt_Z-1))
                subresdat(tt_pos, iElem) = indat(in_pos)
                ! Ensure, that next iteration is in the target range
                do istep=iDof,target_dofs
  ! - ansatz indices are arranged in layers. within each layer, the total
  !   degree remains constant.
  ! - within each layer, we have blocks. within a block, ansfuncz is
  !   constant, y counts up and x accordingly down.
  ! - within each block, we have items. each item represents one particular
  !   combination of ansfuncx, -y, and -z degrees.

  if (tt_x .ne. 1) then
    ! next item
    tt_x = tt_x - 1
    tt_y = tt_y + 1
  elseif (tt_y .ne. 1) then
    ! next block
    tt_x = tt_y - 1
    tt_y = 1
    tt_z = tt_z + 1
  else
    ! next layer
    tt_x = tt_z + 1
    tt_y = 1
    tt_z = 1
  end if
                  if ((tt_X <= minord) .and. (tt_Y <= minord) &
                    &                  .and. (tt_Z <= minord) ) EXIT
                end do
                if ((tt_X > minord) .or. (tt_Y > minord) &
                  &                 .or. (tt_Z > minord) ) EXIT
              end do

            end select

          else
            ! Both input and target ar P polynomials
            select case(target_dim)
            case (1)
              subresdat(:minord, iElem) = indat(:minord)

            case (2)
              min_dofs = (minord*(minord+1))/2
              tt_X = 1
              tt_Y = 1
              do iDof=1,min_dofs
  ! integer divisions are no mistake here.
  tt_pos = ((((tt_x - 1) + (tt_y - 1))            &
    &   * (((tt_x - 1) + (tt_y - 1)) + 1)) / 2 + 1) &
    & + (tt_y - 1)
                in_pos = tt_pos
                subresdat(tt_pos, iElem) = indat(in_pos)
  ! - ansatz indices are arranged in layers. within each layer, the total
  !   degree remains constant.
  ! - within each layer, we have blocks. within a block, ansfuncz is
  !   constant, y counts up and x accordingly down.
  ! - within each block, we have items. each item represents one particular
  !   combination of ansfuncx, -y, and -z degrees.
  if (tt_x .ne. 1) then
    ! next item
    tt_x = tt_x - 1
    tt_y = tt_y + 1
  else
    ! next layer
    tt_x = tt_y + 1
    tt_y = 1
  end if
              end do

            case (3)
              min_dofs = ( (minord+2)*((minord*(minord+1))/2) ) / 3
              tt_X = 1
              tt_Y = 1
              tt_Z = 1
              do iDof=1,min_dofs
  ! integer divisions are no mistake here.
  tt_pos = (((tt_x + tt_y + tt_z - 3) &
    &     * (tt_x + tt_y + tt_z - 2) &
    &     * (tt_x + tt_y + tt_z - 1)) &
    &   / 6 + 1)             &
    & + ((tt_z-1) * (tt_x + tt_y + tt_z -2) &
    &   - ((tt_z-2) * (tt_z-1)) / 2) &
    & + (tt_y-1)
  ! integer divisions are no mistake here.
  in_pos = (((tt_x + tt_y + tt_z - 3) &
    &     * (tt_x + tt_y + tt_z - 2) &
    &     * (tt_x + tt_y + tt_z - 1)) &
    &   / 6 + 1)             &
    & + ((tt_z-1) * (tt_x + tt_y + tt_z -2) &
    &   - ((tt_z-2) * (tt_z-1)) / 2) &
    & + (tt_y-1)
                subresdat(tt_pos, iElem) = indat(in_pos)
  ! - ansatz indices are arranged in layers. within each layer, the total
  !   degree remains constant.
  ! - within each layer, we have blocks. within a block, ansfuncz is
  !   constant, y counts up and x accordingly down.
  ! - within each block, we have items. each item represents one particular
  !   combination of ansfuncx, -y, and -z degrees.

  if (tt_x .ne. 1) then
    ! next item
    tt_x = tt_x - 1
    tt_y = tt_y + 1
  elseif (tt_y .ne. 1) then
    ! next block
    tt_x = tt_y - 1
    tt_y = 1
    tt_z = tt_z + 1
  else
    ! next layer
    tt_x = tt_z + 1
    tt_y = 1
    tt_z = 1
  end if
              end do
            end select
          end if

        end select

      end do

      close(fUnit)

    else

      ! No subresolution data at all, allocate the array with size 0.
      allocate(subresdat(0,0))

    end if

  end subroutine atl_subres_import_color


end module atl_subresolution_module