calculation_tree.f90 Source File


Source Code

!-----------------------------------------------------------------------------------------------------------------------------------
! This file is part of ReMKiT1D.
!
! ReMKiT1D is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as 
! published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
!
! ReMKiT1D is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
!
! You should have received a copy of the GNU General Public License along with ReMKiT1D. If not, see <https://www.gnu.org/licenses/>. 
!
! Copyright 2023 United Kingdom Atomic Energy Authority (stefan.mijin@ukaea.uk)
!-----------------------------------------------------------------------------------------------------------------------------------
module calculation_tree_class
    !! author: Stefan Mijin 
    !! 
    !! Houses the calculation tree class and the relevant node class. 

    use data_kinds                  ,only: rk, ik
    use runtime_constants           ,only: debugging, assertions
    use god_objects                 ,only: Object
    use assertion_utility           ,only: assert, assertIdentical, assertPure
    use basic_interfaces            ,only: realArrayFunctionGenParam
    use support_functions
    use unary_transforms
    use support_types

    implicit none

    type ,public :: CalculationKernel
        !! Kernel containing calculation node properties
        logical :: additiveMode !! If true will use additive mode for reducing the results of its children. Defaults to false. 

        real(rk) :: constant !! Constant component, defaults to 0 in additive mode and 1 in multiplicative.

        integer(ik) :: leafVarIndex !! Index of variable to be used a the child's result if this node is a leaf

        real(rk)    ,allocatable ,dimension(:) :: unaryRealParams !! Optional real parameters of unary transformation
        integer(ik) ,allocatable ,dimension(:) :: unaryIntParams !! Optional integer parameters of unary transformation
        logical     ,allocatable ,dimension(:) :: unaryLogicalParams !! Optional logical parameters of unary transformation

        character(:) ,allocatable :: unaryTransformationTag 
    end type 

    type, public :: FlatTree 
        !! Flattened calculation tree for pointer-safe copying 

        type(CalculationKernel) ,allocatable ,dimension(:) :: kernels 
        type(IntArray) ,allocatable ,dimension(:) :: children 
        integer(ik) ,allocatable ,dimension(:) :: parent

    end type FlatTree

    type ,public ,extends(Object) :: CalculationNode
        !! Node class for the abstract calculation left child/right sibling tree. Each node has a reference to its leftmost child,
        !! its sibling to the immediate right, and to its parent. 
        !!
        !! Each node has a binary mode that is either additive or multiplicative, with 
        !! multiplicative being the default. This mode is applied to the results of the nodes children, either multiplying or adding them.
        !! 
        !! Each node also has a constant (defaulting to 1 in multiplicative and 0 in additive mode), which is applied to the node's result.
        !!
        !! An optional unary operation can be associated with each node, which is then applied to the node's result after the constant.
        !! The unary operation can be parameterized with real, integer, or logical parameters.
        !!
        !! Finally, if a node doesn't have a child (it is a leaf), it must have a nonzero index associated with a passed RealArray(:)
        !! list of variables, with the associated values then treated as the missing child's result.  

        type(CalculationNode) ,pointer :: leftChild => null()
        type(CalculationNode) ,pointer :: rightSibling => null()
        type(CalculationNode) ,pointer :: parent => null()

        type(CalculationKernel) :: kernel 

        procedure(realArrayFunctionGenParam) ,pointer ,nopass :: unaryTransform => null() !! Optional unary transformation

        contains

        procedure ,public :: addChild 
        procedure ,public :: init => initNode
        procedure ,public :: evaluate => evaluateNode
        procedure ,public :: destroy => destroyNode

    end type CalculationNode
!-----------------------------------------------------------------------------------------------------------------------------------
    type ,extends(Object) ,public:: CalculationTree

        type(CalculationNode), pointer :: root => null()

        contains

        procedure ,public :: init => initTree
        procedure ,public :: evaluate => evaluateTree
        procedure ,public :: flatten => flattenTree
        procedure ,public :: initFromFlatTree 

        final :: finalizeCalculationTree

    end type CalculationTree
!-----------------------------------------------------------------------------------------------------------------------------------
!-----------------------------------------------------------------------------------------------------------------------------------
    interface 
!-----------------------------------------------------------------------------------------------------------------------------------
    module subroutine initNode(this,additiveMode,constant,leafVarIndex,unaryRealParams,&
                unaryIntParams,unaryLogicalParams,unaryTransformTag)
        !! Calculation node initialization routine

        class(CalculationNode)                         ,intent(inout)  :: this
        logical                              ,optional ,intent(in) :: additiveMode
        real(rk)                             ,optional ,intent(in) :: constant
        integer(ik)                          ,optional ,intent(in) :: leafVarIndex
        real(rk)    ,dimension(:)            ,optional ,intent(in) :: unaryRealParams
        integer(ik) ,dimension(:)            ,optional ,intent(in) :: unaryIntParams
        logical     ,dimension(:)            ,optional ,intent(in) :: unaryLogicalParams
        character(*)                         ,optional ,intent(in) :: unaryTransformTag

    end subroutine initNode
!-----------------------------------------------------------------------------------------------------------------------------------
        module subroutine initTree(this,additiveMode,constant,leafVarIndex,unaryRealParams,&
                                   unaryIntParams,unaryLogicalParams,unaryTransformTag)
            !! Calculation tree initialization routine

            class(CalculationTree)                         ,intent(inout)  :: this
            logical                              ,optional ,intent(in) :: additiveMode
            real(rk)                             ,optional ,intent(in) :: constant
            integer(ik)                          ,optional ,intent(in) :: leafVarIndex
            real(rk)    ,dimension(:)            ,optional ,intent(in) :: unaryRealParams
            integer(ik) ,dimension(:)            ,optional ,intent(in) :: unaryIntParams
            logical     ,dimension(:)            ,optional ,intent(in) :: unaryLogicalParams
            character(*)                         ,optional ,intent(in) :: unaryTransformTag

        end subroutine initTree
!-----------------------------------------------------------------------------------------------------------------------------------
        module subroutine addChild(this,additiveMode,constant,leafVarIndex,unaryRealParams,&
                    unaryIntParams,unaryLogicalParams,unaryTransformTag)
            !! Initialize a child node of this node with given properties

            class(CalculationNode)               ,target   ,intent(inout)  :: this
            logical                              ,optional ,intent(in) :: additiveMode
            real(rk)                             ,optional ,intent(in) :: constant
            integer(ik)                          ,optional ,intent(in) :: leafVarIndex
            real(rk)    ,dimension(:)            ,optional ,intent(in) :: unaryRealParams
            integer(ik) ,dimension(:)            ,optional ,intent(in) :: unaryIntParams
            logical     ,dimension(:)            ,optional ,intent(in) :: unaryLogicalParams
            character(*)                         ,optional ,intent(in) :: unaryTransformTag

        end subroutine addChild
!-----------------------------------------------------------------------------------------------------------------------------------
        pure module recursive function evaluateNode(this,inputArray) result(res)
            !! Recursively evaluate nodes, using the inputArray variables for leaf values

            class(CalculationNode)        ,intent(in) :: this
            type(RealArray) ,dimension(:) ,intent(in) :: inputArray
            real(rk) ,allocatable ,dimension(:)       :: res
 
        end function evaluateNode
!-----------------------------------------------------------------------------------------------------------------------------------
        pure module function evaluateTree(this,inputArray) result(res)
            !! Call tree's root node evaluate

            class(CalculationTree)        ,intent(in) :: this
            type(RealArray) ,dimension(:) ,intent(in) :: inputArray
            real(rk) ,allocatable ,dimension(:)       :: res
 
        end function evaluateTree
!-----------------------------------------------------------------------------------------------------------------------------------
        module function flattenTree(this) result(res)
            !! Flatten tree into FlatTree object

            class(CalculationTree)        ,intent(in) :: this
            type(FlatTree)                            :: res
 
        end function flattenTree
!-----------------------------------------------------------------------------------------------------------------------------------
        module subroutine initFromFlatTree(this,fTree)
            !! Calculation tree initialization routine using a FlatTree object

            class(CalculationTree)           ,intent(inout)  :: this
            type(FlatTree)                   ,intent(in)     :: fTree

        end subroutine initFromFlatTree
!-----------------------------------------------------------------------------------------------------------------------------------
        pure module recursive subroutine destroyNode(this)

            class(CalculationNode),intent(inout) :: this

        end subroutine destroyNode
!-----------------------------------------------------------------------------------------------------------------------------------
        elemental module subroutine finalizeCalculationTree(this) 

            type(CalculationTree) ,intent(inout) :: this

        end subroutine finalizeCalculationTree 
!-----------------------------------------------------------------------------------------------------------------------------------
    end interface
!-----------------------------------------------------------------------------------------------------------------------------------
 end module calculation_tree_class
!-----------------------------------------------------------------------------------------------------------------------------------