Skip to content
Snippets Groups Projects
Select Git revision
  • 8f81023930a73ab726e3d28d800776b0dba31a78
  • master default protected
  • staggered-max
  • unifed-object
  • no_Amalgamated
  • standard_stb
  • parallel_doc_fix
  • release_0.9.3
  • cmake_mpich_tests
  • update_install
  • external_VORO
  • cmake_add_soversion
  • iterative_method
  • cmake_install
  • fixes_042023
  • tensor_max
  • personal/schulz3/tensor_max
  • releases/v0.9
  • ForceBasedDevel
  • refactor
  • feature/simple_test_cases
  • v0.9.3
  • v0.9.2
  • v0.9.1
  • v0.9.0
  • v0.9.0-rc2
26 results

ALL_module.F90

Blame
  • ALL_module.F90 21.60 KiB
    !Copyright 2018-2020 Rene Halver, Forschungszentrum Juelich GmbH, Germany
    !Copyright 2018-2020 Godehard Sutmann, Forschungszentrum Juelich GmbH, Germany
    !Copyright 2019-2020 Stephan Schulz, Ruhr-Universität Bochum, Germany
    !
    !Redistribution and use in source and binary forms, with or without modification, are
    !permitted provided that the following conditions are met:
    !
    !1. Redistributions of source code must retain the above copyright notice, this list
    !   of conditions and the following disclaimer.
    !
    !2. Redistributions in binary form must reproduce the above copyright notice, this
    !   list of conditions and the following disclaimer in the documentation and/or
    !   other materials provided with the distribution.
    !
    !3. Neither the name of the copyright holder nor the names of its contributors
    !   may be used to endorse or promote products derived from this software without
    !   specific prior written permission.
    !
    !THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
    !EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    !OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
    !SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
    !INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
    !TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
    !BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    !CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
    !ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    !SUCH DAMAGE.
    ! -DCMAKE_Fortran_FLAGS='-std=f2003 -Wall -Wextra -fbacktrace' -DCM_ALL_FORTRAN=ON -DCMAKE_BUILD_TYPE=Debug -DCM_ALL_DEBUG=ON
    
    !> The function API for ALL
    !!
    !! The ``*_c`` functions should never be called directly, but their non suffixed
    !! counterparts should. Safety checks and conveniences provided by Fortran are
    !! available there. For a simple example on how to use this see ``examples/``
    !! directory.
    module ALL_module
        use iso_c_binding
        use iso_fortran_env
        implicit none
        private
        ! The different loadbalancing methods. Must be kept in sync with C side.
        integer(c_int), public, parameter :: ALL_STAGGERED = 0
        integer(c_int), public, parameter :: ALL_TENSOR = 1
        integer(c_int), public, parameter :: ALL_UNSTRUCTURED = 2
    #ifdef ALL_VORONOI_ACTIVE
        integer(c_int), public, parameter :: ALL_VORONOI = 3
    #endif
        integer(c_int), public, parameter :: ALL_HISTOGRAM = 4
        integer(c_int), public, parameter :: ALL_UNIMPLEMENTED = 128
        ! The different error IDs. Must be kept in sync with CustomException class
        integer(c_int), public, parameter :: ALL_ERROR_GENERIC = 1
        integer(c_int), public, parameter :: ALL_ERROR_POINTDIMENSIONMISSMATCH = 2
        integer(c_int), public, parameter :: ALL_ERROR_INVALIDCOMMTYPE = 3
        integer(c_int), public, parameter :: ALL_ERROR_INVALIDARGUMENT = 4
        integer(c_int), public, parameter :: ALL_ERROR_OUTOFBOUNDS = 5
        integer(c_int), public, parameter :: ALL_ERROR_INTERNAL = 6
        integer(c_int), public, parameter :: ALL_ERROR_FILESYSTEM = 6
        ! Maximum character length of error descriptions
        integer, public, parameter :: ALL_ERROR_LENGTH = 1024
        ! Direct interface with C wrapper
        ! TODO add intent() to dummy arguments
        interface
            function all_init_c(method, dim, gamma) result(this) bind(C)
                use iso_c_binding
                integer(c_int), value :: method
                integer(c_int), value :: dim
                real(c_double), value :: gamma
                type(c_ptr) :: this
            end function
            subroutine all_finalize_c(obj) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
            end subroutine
            subroutine all_set_gamma_c(obj, gamma) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                real(c_double), value :: gamma
            end subroutine
            subroutine all_set_proc_grid_params_c(obj, nloc, loc, nsize, size) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: nloc
                integer(c_int), dimension(nloc) :: loc
                integer(c_int), value :: nsize
                integer(c_int), dimension(nsize) :: size
            end subroutine
            subroutine all_set_proc_tag_c(obj, tag) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: tag
            end subroutine
            subroutine all_set_min_domain_size_c(obj, dim, domain_size) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: dim
                real(c_double), dimension(dim) :: domain_size
            end subroutine
            subroutine all_set_work_c(obj, work) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                real(c_double), value :: work
            end subroutine
            subroutine all_set_work_multi_c(obj, work, dim) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: dim
                real(c_double), dimension(dim) :: work
            end subroutine
            subroutine all_set_vertices_c(obj, n, dim, vertices) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: n
                integer(c_int), value :: dim
                real(c_double), dimension(n*dim) :: vertices
            end subroutine
            subroutine all_set_communicator_c(obj, comm) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer, value :: comm
            end subroutine
            subroutine all_set_sys_size_c(obj, size, dim) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: dim
                real(c_double), dimension(dim) :: size
            end subroutine
            subroutine all_set_method_data_histogram_c(obj, nbins) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), dimension(3) :: nbins
            end subroutine
            subroutine all_setup_c(obj) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
            end subroutine
            subroutine all_balance_c(obj) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
            end subroutine
            subroutine all_get_gamma_c(obj, gamma) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                real(c_double) :: gamma
            end subroutine
            subroutine all_get_number_of_vertices_c(obj, n) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int) :: n
            end subroutine
            subroutine all_get_vertices_c(obj, n, vertices) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: n
                real(c_double), dimension(*) :: vertices
            end subroutine
            subroutine all_get_prev_vertices_c(obj, n, vertices) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: n
                real(c_double), dimension(*) :: vertices
            end subroutine
            subroutine all_get_dimension_c(obj,dim) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int) :: dim
            end subroutine
            subroutine all_get_length_of_work_c(obj, length) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int) :: length
            end subroutine
            subroutine all_get_work_c(obj, work) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                real(c_double) :: work
            end subroutine
            subroutine all_get_work_array_c(obj, work, length) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: length
                real(c_double), dimension(length) :: work
            end subroutine
    #ifdef ALL_VTK_OUTPUT
            subroutine all_print_vtk_outlines_c(obj, step) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: step
            end subroutine
            subroutine all_print_vtk_vertices_c(obj, step) bind(C)
                use iso_c_binding
                type(c_ptr), value :: obj
                integer(c_int), value :: step
            end subroutine
    #endif
            function all_errno_c() result(errno) bind(C)
                use iso_c_binding
                integer(c_int) :: errno
            end function
            subroutine all_reset_errno_c() bind(C)
            end subroutine
            subroutine all_errdesc_c(text, length) bind(C)
                use iso_c_binding
                character(len=1,kind=c_char) :: text(*)
                integer(c_size_t), value :: length
            end subroutine
        end interface
    
        !> The object oriented API is this object. It contains all relevant functions
        type, public :: ALL_t
            type(c_ptr), private :: object = C_NULL_PTR !< pointer to C++ object used on C side
            integer, private :: dim = 0 !< dimensionality of system, set during init
        contains
            procedure :: init => ALL_init
            procedure :: finalize => ALL_finalize
            procedure :: set_gamma => ALL_set_gamma
            procedure :: set_proc_grid_params => ALL_set_proc_grid_params
            procedure :: set_proc_tag => ALL_set_proc_tag
            procedure :: set_min_domain_size => ALL_set_min_domain_size
            procedure :: set_work => ALL_set_work
            procedure :: set_work_multi => ALL_set_work_multi
            procedure :: set_vertices => ALL_set_vertices
    #ifdef ALL_USE_F08
            procedure :: set_communicator => ALL_set_communicator_f08
    #else
            procedure :: set_communicator => ALL_set_communicator_int
    #endif
            procedure :: set_sys_size => ALL_set_sys_size
            procedure :: set_method_data_histgram => ALL_set_method_data_histgram
            procedure :: setup => ALL_setup
            procedure :: balance => ALL_balance
            procedure :: get_gamma => ALL_get_gamma
            procedure :: get_number_of_vertices => ALL_get_number_of_vertices
            procedure :: get_vertices => ALL_get_vertices
            procedure :: get_vertices_alloc => ALL_get_vertices_alloc
            procedure :: get_prev_vertices => ALL_get_prev_vertices
            procedure :: get_dimension => ALL_get_dimension
            procedure :: get_length_of_work => ALL_get_length_of_work
            procedure :: get_work => ALL_get_work
            procedure :: get_work_array => ALL_get_work_array
    #ifdef ALL_VTK_OUTPUT
            procedure :: print_vtk_outlines => ALL_print_vtk_outlines
            procedure :: print_vtk_vertices => ALL_print_vtk_vertices
    #endif
        end type
    
        ! This is the old, but still supported API of separate functions
        public :: ALL_init
        public :: ALL_finalize
        public :: ALL_set_gamma
        public :: ALL_set_proc_grid_params
        public :: ALL_set_proc_tag
        public :: ALL_set_min_domain_size
        public :: ALL_set_work
        public :: ALL_set_work_multi
        public :: ALL_set_vertices
        public :: ALL_set_communicator
        public :: ALL_set_sys_size
        public :: ALL_set_method_data_histgram
        public :: ALL_setup
        public :: ALL_balance
        public :: ALL_get_gamma
        public :: ALL_get_number_of_vertices
        public :: ALL_get_vertices
        public :: ALL_get_vertices_alloc
        public :: ALL_get_prev_vertices
        public :: ALL_get_dimension
        public :: ALL_get_length_of_work
        public :: ALL_get_work
        public :: ALL_get_work_array
    #ifdef ALL_VTK_OUTPUT
        public :: ALL_print_vtk_outlines
        public :: ALL_print_vtk_vertices
    #endif
        public :: ALL_error
        public :: ALL_reset_error
        public :: ALL_error_description
    
        interface ALL_set_communicator
            module procedure ALL_set_communicator_int
    #ifdef ALL_USE_F08
            module procedure ALL_set_communicator_f08
    #endif
        end interface
    contains
        !> Initialises the loadbalancer
        subroutine ALL_init(this, method, dim, gamma)
            class(ALL_t), intent(out) :: this !< teh ALL object is returned
            integer, intent(in) :: method !< Must be one of the ALL_* method values
            integer, intent(in) :: dim !< dimensionality of system
            real(c_double), intent(in) :: gamma !< gamma value for load balancer (ignored for TENSOR and STAGGERED)
            this%object = all_init_c(method, dim, gamma)
            this%dim = dim
        end subroutine
        !> Delete the loadbalance object
        subroutine ALL_finalize(this)
            class(ALL_t), intent(in) :: this
            call all_finalize_c(this%object)
        end subroutine
        !> Set gamma value for load balancer
        subroutine ALL_set_gamma(this, gamma)
            class(ALL_t), intent(in) :: this
            real(c_double), intent(in) :: gamma
            call all_set_gamma_c(this%object, gamma)
        end subroutine
        !> Set the grid parameters for this process
        subroutine ALL_set_proc_grid_params(this, loc, ranks)
            class(ALL_t), intent(in) :: this
            integer, dimension(this%dim), intent(in) :: loc !< index of domain in `dim` directions (0-indexed!)
            integer, dimension(this%dim), intent(in) :: ranks !< total number of domains in `dim` directions
            call all_set_proc_grid_params_c(this%object, this%dim, loc, this%dim, ranks)
        end subroutine
        !> Set process identifying tag for output
        subroutine ALL_set_proc_tag(this, tag)
            class(ALL_t), intent(in) :: this
            integer, intent(in) :: tag !< tag of local process, only output in VTK outlines
            call all_set_proc_tag_c(this%object, tag)
        end subroutine
        !> Set a minimum domain size
        subroutine ALL_set_min_domain_size(this, domain_size)
            class(ALL_t), intent(in) :: this
            real(c_double), dimension(this%dim), intent(in) :: domain_size !< minimum domain size
            call all_set_min_domain_size_c(this%object, this%dim, domain_size)
        end subroutine
        !> Set the work of this process
        subroutine ALL_set_work(this, work)
            class(ALL_t), intent(in) :: this
            real(c_double), intent(in) :: work !< work of this domain
            call all_set_work_c(this%object, work)
        end subroutine
        !> Set multi dimensional work of this process
        subroutine ALL_set_work_multi(this, work)
            class(ALL_t), intent(in) :: this
            real(c_double), dimension(:), intent(in) :: work !< multi dimensional work of this domain
    #ifndef NDEBUG
            if(size(work) /= this%dim) then
                write(error_unit, '(a)') "ALL_set_work_multi: Wrong dimension for work"
                stop
            endif
    #endif
            call all_set_work_multi_c(this%object, work, size(work))
        end subroutine
        !> Set new vertices
        !!
        !! @todo write interface for single rank array of vertices
        subroutine ALL_set_vertices(this, vertices)
            class(ALL_t), intent(in) :: this
            real(c_double), dimension(:,:), intent(in) :: vertices !< vertices of domain, for `n` domains must have shape: (dim,n)
    #ifndef NDEBUG
            if(size(vertices,1) /= this%dim) then
                write(error_unit,'(a)') "ALL_set_vertices: Wrong dimension for vertices"
                stop
            endif
    #endif
            call all_set_vertices_c(this%object, size(vertices,2), this%dim, vertices)
        end subroutine
        !> Set the MPI communicator with an mpi_f08 object
    #ifdef ALL_USE_F08
        subroutine ALL_set_communicator_f08(this, comm)
            use mpi_f08
            class(ALL_t), intent(in) :: this
            type(MPI_Comm), intent(in) :: comm !< MPI Communicator
            call all_set_communicator_c(this%object, comm%mpi_val)
        end subroutine
    #endif
        !> Set the MPI communicator with an ``mpi`` oder ``mpif.h`` communicator
        subroutine ALL_set_communicator_int(this, comm)
            class(ALL_t), intent(in) :: this
            integer, intent(in) :: comm !< MPI Communicator, not type checked!
            call all_set_communicator_c(this%object, comm)
        end subroutine
        !> Set size of system, which is required for the histogram method
        subroutine ALL_set_sys_size(this, syssize)
            class(ALL_t), intent(in) :: this
            real(c_double), dimension(:), intent(in) :: syssize !< system size
    #ifndef NDEBUG
            if(size(syssize) /= this%dim) then
                write(error_unit, '(a)') "ALL_set_size: Wrong dimension for size"
                stop
            endif
    #endif
            call all_set_sys_size_c(this%object, syssize, size(syssize))
        end subroutine
        !> Set number of bins for histogram method
        subroutine ALL_set_method_data_histgram(this, nbins)
            class(ALL_t), intent(in) :: this
            integer(c_int), dimension(3), intent(in) :: nbins !< Number of bins per dimension
            call all_set_method_data_histogram_c(this%object, nbins)
        end subroutine
        !> Set up the loadbalancer
        subroutine ALL_setup(this)
            class(ALL_t), intent(in) :: this
            call all_setup_c(this%object)
        end subroutine
        !> Run loadbalancer and calculate new vertices
        subroutine ALL_balance(this)
            class(ALL_t), intent(in) :: this
            call all_balance_c(this%object)
        end subroutine
        !> Retrieve currently set gamma value of balancer
        subroutine ALL_get_gamma(this, gamma)
            class(ALL_t), intent(in) :: this
            real(c_double), intent(out) :: gamma
            call all_get_gamma_c(this%object, gamma)
        end subroutine
        !> Retrieve number of vertices for current vertices
        subroutine ALL_get_number_of_vertices(this, n)
            class(ALL_t), intent(in) :: this
            integer(c_int), intent(out) :: n !< set to number of new vertices
            call all_get_number_of_vertices_c(this%object, n)
        end subroutine
        !> Retrieve current vertices
        subroutine ALL_get_vertices(this, vertices)
            class(ALL_t), intent(in) :: this
            real(c_double), dimension(:,:), intent(out) :: vertices !< set to new vertices, must be exact size (dim,n)
            integer(c_int) :: n_verts
            call this%get_number_of_vertices(n_verts)
    #ifndef NDEBUG
            if(size(vertices,1) /= this%dim .or. size(vertices,2) < n_verts) then
                write(error_unit,'(a)') "ALL_get_vertices: vertices array not large enough!"
                stop
            endif
    #endif
            call all_get_vertices_c(this%object, n_verts, vertices)
        end subroutine
        !> Same function as get_vertices, but takes an allocatable array, and resizes automatically
        subroutine ALL_get_vertices_alloc(this, vertices)
            class(ALL_t), intent(in) :: this
            real(c_double), dimension(:,:), allocatable, intent(inout) :: vertices !< set to new vertices, may be reallocated to fit
            integer(c_int) :: n_verts
            call this%get_number_of_vertices(n_verts)
            if(allocated(vertices)) then
                if(size(vertices,1) /= this%dim .or. size(vertices,2) < n_verts) then
                    deallocate(vertices)
                endif
            endif
            if(.not.allocated(vertices)) allocate(vertices(this%dim, n_verts))
            call all_get_vertices_c(this%object, n_verts, vertices)
        end subroutine
        !> Retrieve vertices from before loadbalancing
        subroutine ALL_get_prev_vertices(this, vertices)
            class(ALL_t), intent(in) :: this
            real(c_double), dimension(:,:), intent(out) :: vertices !< set to prev vertices, must be exact size (dim,n), unchecked!
    #ifndef NDEBUG
            ! TODO Check against number of vertices not only dimensionality
            if(size(vertices,1) /= this%dim) then
                write(error_unit,'(a)') "ALL_get_prev_vertices: vertices array not large enough!"
                stop
            endif
    #endif
            call all_get_prev_vertices_c(this%object, size(vertices,2), vertices)
        end subroutine
        !> Get current dimension from loadbalancer
        subroutine ALL_get_dimension(this, dim)
            class(ALL_t), intent(in) :: this
            integer(c_int), intent(out) :: dim
            call all_get_dimension_c(this%object,dim)
        end subroutine
        !> Retrieve length of work array
        subroutine ALL_get_length_of_work(this, length)
            class(ALL_t), intent(in) :: this
            integer(c_int), intent(out) :: length
            call all_get_length_of_work_c(this%object, length)
        end subroutine
        !> Retrieve first element of work array
        subroutine ALL_get_work(this, work)
            class(ALL_t), intent(in) :: this
            real(c_double), intent(out) :: work
            call all_get_work_c(this%object, work)
        end subroutine
        !> Retrieve work array, which must already be the correct size
        subroutine ALL_get_work_array(this, work)
            class(ALL_t), intent(in) :: this
            real(c_double), dimension(:), intent(out) :: work
            integer :: length
            call ALL_get_length_of_work(this, length)
            if(size(work) /= length) then
                write(error_unit,'(a)') "ALL_get_work_array: work has wrong length!"
                stop
            endif
            call all_get_work_array_c(this%object, work, size(work))
        end subroutine
    #ifdef ALL_VTK_OUTPUT
        !> Print VTK outlines (must be enabled in build step)
        subroutine ALL_print_vtk_outlines(this, step)
            class(ALL_t), intent(in) :: this
            integer(c_int), intent(in) :: step !< current step, used for filename
            call all_print_vtk_outlines_c(this%object, step)
        end subroutine
        !> Print VTK domain vertices (must be enabled in build step)
        subroutine ALL_print_vtk_vertices(this, step)
            class(ALL_t), intent(in) :: this
            integer(c_int), intent(in) :: step !< current step, used for filename
            call all_print_vtk_vertices_c(this%object, step)
        end subroutine
    #endif
        function ALL_error() result(error)
            integer :: error
            error = all_errno_c()
        end function
        subroutine ALL_reset_error()
            call all_reset_errno_c()
        end subroutine
        function ALL_error_description() result(desc)
            character(len=ALL_ERROR_LENGTH) :: desc
            call all_errdesc_c(desc, int(ALL_ERROR_LENGTH,c_size_t))
        end function
    end module
    
    ! VIM modeline for indentation
    ! vim: sw=4 et