LCOV - code coverage report
Current view: top level - src/common - d3_poly.F (source / functions) Hit Total Coverage
Test: CP2K Regtests (git:262480d) Lines: 54 850 6.4 %
Date: 2024-11-22 07:00:40 Functions: 3 41 7.3 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------------------------!
       2             : !   CP2K: A general program to perform molecular dynamics simulations                              !
       3             : !   Copyright 2000-2024 CP2K developers group <https://cp2k.org>                                   !
       4             : !                                                                                                  !
       5             : !   SPDX-License-Identifier: GPL-2.0-or-later                                                      !
       6             : !--------------------------------------------------------------------------------------------------!
       7             : 
       8             : ! **************************************************************************************************
       9             : !>   \brief
      10             : !>     Routines to efficiently handle dense polynomial in 3 variables up to
      11             : !>     a given degree.
      12             : !>     Multiplication, partial evaluation, affine transform (change of reference
      13             : !>     system), differentiation are efficiently implemented.
      14             : !>     some functions accept or return several polynomial together,
      15             : !>     these have to have all the same size, and are stored one after the other
      16             : !>     in an unique 1d array. This gives them an easy handling and even seem to
      17             : !>     be faster than the transposed layout.
      18             : !>   \note
      19             : !>     not all routines have been fully optimized.
      20             : !>     original available also with a BSD style license
      21             : !>   \author Fawzi Mohamed
      22             : ! **************************************************************************************************
      23             : MODULE d3_poly
      24             : 
      25             :    USE kinds,                           ONLY: dp
      26             : 
      27             : !$ USE OMP_LIB, ONLY: omp_get_max_threads, omp_get_thread_num, omp_get_num_threads
      28             : 
      29             : #include "../base/base_uses.f90"
      30             : 
      31             :    IMPLICIT NONE
      32             : 
      33             :    PRIVATE
      34             : 
      35             :    PUBLIC :: poly_size1, poly_size2, poly_size3, &
      36             :              grad_size3, &
      37             :              poly_affine_t3, &
      38             :              poly_p_eval2b, &
      39             :              poly_p_eval3b, poly_cp2k2d3, &
      40             :              poly_padd_uneval3b, poly_padd_uneval2b, &
      41             :              poly_affine_t3t, poly_d32cp2k, init_d3_poly_module
      42             : 
      43             : #ifdef FD_DEBUG
      44             : #define IF_CHECK(x,y) x
      45             : #else
      46             : #define IF_CHECK(x,y) y
      47             : #endif
      48             : 
      49             :    CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'd3_poly'
      50             : ! maximum grad for cached values
      51             :    INTEGER, PUBLIC, PARAMETER :: max_grad2 = 5
      52             :    INTEGER, PUBLIC, PARAMETER :: max_grad3 = 3
      53             :    INTEGER, PUBLIC, PARAMETER :: cached_dim1 = max_grad2 + 1
      54             :    INTEGER, PUBLIC, PARAMETER :: cached_dim2 = (max_grad2 + 1)*(max_grad2 + 2)/2
      55             :    INTEGER, PUBLIC, PARAMETER :: cached_dim3 = (max_grad3 + 1)*(max_grad3 + 2)*(max_grad3 + 3)/6
      56             : 
      57             : ! cached index -> monomial exponents
      58             :    LOGICAL, SAVE                           :: module_initialized = .FALSE.
      59             :    INTEGER, SAVE, DIMENSION(2, cached_dim2) :: a_mono_exp2
      60             :    INTEGER, SAVE, DIMENSION(3, cached_dim3) :: a_mono_exp3
      61             :    INTEGER, SAVE, DIMENSION(cached_dim3)   :: a_reduce_idx3
      62             :    INTEGER, SAVE, DIMENSION(3, cached_dim3) :: a_deriv_idx3
      63             :    INTEGER, SAVE, DIMENSION(cached_dim2, cached_dim2) :: a_mono_mult2
      64             :    INTEGER, SAVE, DIMENSION(cached_dim3, cached_dim3) :: a_mono_mult3
      65             :    INTEGER, SAVE, DIMENSION(4, cached_dim3) :: a_mono_mult3a
      66             : 
      67             : CONTAINS
      68             : 
      69             : ! **************************************************************************************************
      70             : !> \brief initialization of the cache, is called by functions in this module
      71             : !> that use cached values
      72             : ! **************************************************************************************************
      73       28736 :    SUBROUTINE init_d3_poly_module()
      74             :       INTEGER                                            :: grad, i, ii, ij, j, nthreads, subG
      75             :       INTEGER, DIMENSION(2)                              :: monoRes2
      76             :       INTEGER, DIMENSION(3)                              :: monoRes3
      77             : 
      78       28736 :       nthreads = 1
      79       28736 : !$    nthreads = OMP_GET_NUM_THREADS()
      80       28736 :       IF (nthreads /= 1) CPABORT("init_d3_poly_module must not be called within OMP PARALLEL")
      81             : 
      82       28736 :       IF (module_initialized) RETURN
      83             : 
      84             :       ii = 1
      85       44051 :       DO grad = 0, max_grad2
      86      176204 :          DO i = grad, 0, -1
      87      132153 :             a_mono_exp2(1, ii) = i
      88      132153 :             a_mono_exp2(2, ii) = grad - i
      89      169911 :             ii = ii + 1
      90             :          END DO
      91             :       END DO
      92             :       ii = 1
      93       31465 :       DO grad = 0, max_grad3
      94       94395 :          DO i = grad, 0, -1
      95      213962 :             DO j = grad - i, 0, -1
      96      125860 :                a_mono_exp3(1, ii) = i
      97      125860 :                a_mono_exp3(2, ii) = j
      98      125860 :                a_mono_exp3(3, ii) = grad - i - j
      99      188790 :                ii = ii + 1
     100             :             END DO
     101             :          END DO
     102             :       END DO
     103      132153 :       DO ii = 1, cached_dim3
     104      125860 :          subG = a_mono_exp3(2, ii) + a_mono_exp3(3, ii)
     105      132153 :          a_reduce_idx3(ii) = subG*(subG + 1)/2 + a_mono_exp3(3, ii) + 1
     106             :       END DO
     107      132153 :       DO ii = 1, cached_dim3
     108      125860 :          IF (a_mono_exp3(1, ii) > 0) THEN
     109       62930 :             a_deriv_idx3(1, ii) = mono_index3(a_mono_exp3(1, ii) - 1, a_mono_exp3(2, ii), a_mono_exp3(3, ii))
     110             :          ELSE
     111       62930 :             a_deriv_idx3(1, ii) = 0
     112             :          END IF
     113      125860 :          IF (a_mono_exp3(2, ii) > 0) THEN
     114       62930 :             a_deriv_idx3(2, ii) = mono_index3(a_mono_exp3(1, ii), a_mono_exp3(2, ii) - 1, a_mono_exp3(3, ii))
     115             :          ELSE
     116       62930 :             a_deriv_idx3(2, ii) = 0
     117             :          END IF
     118      132153 :          IF (a_mono_exp3(3, ii) > 0) THEN
     119       62930 :             a_deriv_idx3(3, ii) = mono_index3(a_mono_exp3(1, ii), a_mono_exp3(2, ii), a_mono_exp3(3, ii) - 1)
     120             :          ELSE
     121       62930 :             a_deriv_idx3(3, ii) = 0
     122             :          END IF
     123             :       END DO
     124      138446 :       DO ii = 1, cached_dim2
     125     1592129 :          DO ij = ii, cached_dim2
     126     4361049 :             monoRes2 = a_mono_exp2(:, ii) + a_mono_exp2(:, ij)
     127     1453683 :             a_mono_mult2(ii, ij) = mono_index2(monoRes2(1), monoRes2(2)) + 1
     128     1585836 :             a_mono_mult2(ij, ii) = a_mono_mult2(ii, ij)
     129             :          END DO
     130             :       END DO
     131      132153 :       DO ii = 1, cached_dim3
     132     1453683 :          DO ij = ii, cached_dim3
     133     5286120 :             monoRes3 = a_mono_exp3(:, ii) + a_mono_exp3(:, ij)
     134     1321530 :             a_mono_mult3(ii, ij) = mono_index3(monoRes3(1), monoRes3(2), monoRes3(3)) + 1
     135     1447390 :             a_mono_mult3(ij, ii) = a_mono_mult3(ii, ij)
     136             :          END DO
     137             :       END DO
     138             :       ii = 1
     139      132153 :       DO i = 1, cached_dim3
     140      635593 :          DO j = 1, 4
     141      503440 :             a_mono_mult3a(j, i) = a_mono_mult3(j, i)
     142      629300 :             ii = ii + 1
     143             :          END DO
     144             :       END DO
     145             : 
     146        6293 :       module_initialized = .TRUE.
     147             :    END SUBROUTINE
     148             : 
     149             : ! **************************************************************************************************
     150             : !> \brief size of a polynomial in x up to the given degree
     151             : !> \param maxgrad ...
     152             : !> \return ...
     153             : ! **************************************************************************************************
     154           0 :    PURE FUNCTION poly_size1(maxgrad) RESULT(res)
     155             :       INTEGER, INTENT(in)                                :: maxgrad
     156             :       INTEGER                                            :: res
     157             : 
     158           0 :       res = maxgrad + 1
     159           0 :    END FUNCTION
     160             : 
     161             : ! **************************************************************************************************
     162             : !> \brief size of a polynomial in x,y up to the given degree
     163             : !> \param maxgrad ...
     164             : !> \return ...
     165             : ! **************************************************************************************************
     166           0 :    PURE FUNCTION poly_size2(maxgrad) RESULT(res)
     167             :       INTEGER, INTENT(in)                                :: maxgrad
     168             :       INTEGER                                            :: res
     169             : 
     170           0 :       res = (maxgrad + 1)*(maxgrad + 2)/2
     171           0 :    END FUNCTION
     172             : 
     173             : ! **************************************************************************************************
     174             : !> \brief size of a polynomial in x,y,z up to the given degree
     175             : !> \param maxgrad ...
     176             : !> \return ...
     177             : ! **************************************************************************************************
     178           0 :    PURE FUNCTION poly_size3(maxgrad) RESULT(res)
     179             :       INTEGER, INTENT(in)                                :: maxgrad
     180             :       INTEGER                                            :: res
     181             : 
     182           0 :       res = (maxgrad + 1)*(maxgrad + 2)*(maxgrad + 3)/6
     183           0 :    END FUNCTION
     184             : 
     185             : ! **************************************************************************************************
     186             : !> \brief max grad for a polynom of the given size
     187             : !> \param n ...
     188             : !> \return ...
     189             : ! **************************************************************************************************
     190           0 :    PURE FUNCTION grad_size1(n) RESULT(res)
     191             :       INTEGER, INTENT(in)                                :: n
     192             :       INTEGER                                            :: res
     193             : 
     194           0 :       res = n - 1
     195           0 :    END FUNCTION
     196             : 
     197             : ! **************************************************************************************************
     198             : !> \brief max grad for a polynom of the given size
     199             : !> \param n ...
     200             : !> \return ...
     201             : ! **************************************************************************************************
     202           0 :    PURE FUNCTION grad_size2(n) RESULT(res)
     203             :       INTEGER, INTENT(in)                                :: n
     204             :       INTEGER                                            :: res
     205             : 
     206           0 :       res = INT(FLOOR(0.5_dp*(SQRT(1.0_dp + 8.0_dp*REAL(n, dp)) - 1.0_dp) - 2.e-6_dp))
     207           0 :    END FUNCTION
     208             : 
     209             : ! **************************************************************************************************
     210             : !> \brief max grad for a polynom of the given size
     211             : !> \param n ...
     212             : !> \return ...
     213             : ! **************************************************************************************************
     214           0 :    PURE FUNCTION grad_size3(n) RESULT(res)
     215             :       INTEGER, INTENT(in)                                :: n
     216             :       INTEGER                                            :: res
     217             : 
     218             :       INTEGER                                            :: nn
     219             :       REAL(dp)                                           :: g1
     220             : 
     221           0 :       IF (n < 1) THEN
     222             :          res = -1
     223             :       ELSE
     224           0 :          nn = n*6
     225           0 :          g1 = (108.0_dp*nn + 12.0_dp*SQRT(81.0_dp*nn*nn - 12.0_dp))**(1.0_dp/3.0_dp)
     226           0 :          res = FLOOR(g1/6.0_dp + 2.0_dp/g1 - 1.0_dp - 2.e-6_dp)
     227             :       END IF
     228           0 :    END FUNCTION
     229             : 
     230             : ! **************************************************************************************************
     231             : !> \brief 0-based index of monomial of the given degree
     232             : !> \param i ...
     233             : !> \return ...
     234             : ! **************************************************************************************************
     235           0 :    PURE FUNCTION mono_index1(i) RESULT(res)
     236             :       INTEGER, INTENT(in)                                :: i
     237             :       INTEGER                                            :: res
     238             : 
     239           0 :       res = i
     240           0 :    END FUNCTION
     241             : 
     242             : ! **************************************************************************************************
     243             : !> \brief 0-based index of monomial of the given degree
     244             : !> \param i ...
     245             : !> \param j ...
     246             : !> \return ...
     247             : ! **************************************************************************************************
     248     1453683 :    PURE FUNCTION mono_index2(i, j) RESULT(res)
     249             :       INTEGER, INTENT(in)                                :: i, j
     250             :       INTEGER                                            :: res
     251             : 
     252             :       INTEGER                                            :: grad
     253             : 
     254     1453683 :       grad = i + j
     255     1453683 :       res = grad*(grad + 1)/2 + j
     256     1453683 :    END FUNCTION
     257             : 
     258             : ! **************************************************************************************************
     259             : !> \brief 0-based index of monomial of the given degree
     260             : !> \param i ...
     261             : !> \param j ...
     262             : !> \param k ...
     263             : !> \return ...
     264             : ! **************************************************************************************************
     265     1510320 :    PURE FUNCTION mono_index3(i, j, k) RESULT(res)
     266             :       INTEGER, INTENT(in)                                :: i, j, k
     267             :       INTEGER                                            :: res
     268             : 
     269             :       INTEGER                                            :: grad, sgrad
     270             : 
     271     1510320 :       sgrad = j + k
     272     1510320 :       grad = i + sgrad
     273     1510320 :       res = grad*(grad + 1)*(grad + 2)/6 + (sgrad)*(sgrad + 1)/2 + k
     274     1510320 :    END FUNCTION
     275             : 
     276             : ! **************************************************************************************************
     277             : !> \brief exponents of the monomial at the given 0-based index
     278             : !> \param ii ...
     279             : !> \return ...
     280             : ! **************************************************************************************************
     281           0 :    PURE FUNCTION mono_exp1(ii) RESULT(res)
     282             :       INTEGER, INTENT(in)                                :: ii
     283             :       INTEGER                                            :: res
     284             : 
     285           0 :       res = ii
     286           0 :    END FUNCTION
     287             : 
     288             : ! **************************************************************************************************
     289             : !> \brief exponents of the monomial at the given 0-based index
     290             : !> \param ii ...
     291             : !> \return ...
     292             : ! **************************************************************************************************
     293           0 :    PURE FUNCTION mono_exp2(ii) RESULT(res)
     294             :       INTEGER, INTENT(in)                                :: ii
     295             :       INTEGER, DIMENSION(2)                              :: res
     296             : 
     297             :       INTEGER                                            :: grad
     298             : 
     299           0 :       grad = INT(FLOOR(0.5_dp*(SQRT(9.0_dp + 8.0_dp*ii) - 1.0_dp) - 2.e-6_dp))
     300           0 :       res(2) = ii - (grad)*(grad + 1)/2
     301           0 :       res(1) = grad - res(2)
     302           0 :    END FUNCTION
     303             : 
     304             : ! **************************************************************************************************
     305             : !> \brief exponents of the monomial at the given 0-based index
     306             : !> \param n ...
     307             : !> \return ...
     308             : ! **************************************************************************************************
     309           0 :    PURE FUNCTION mono_exp3(n) RESULT(res)
     310             :       INTEGER, INTENT(in)                                :: n
     311             :       INTEGER, DIMENSION(3)                              :: res
     312             : 
     313             :       INTEGER                                            :: grad, grad1, ii, nn
     314             :       REAL(dp)                                           :: g1
     315             : 
     316           0 :       nn = (n + 1)*6
     317           0 :       g1 = (108.0_dp*nn + 12.0_dp*SQRT(81.0_dp*nn*nn - 12.0_dp))**(1.0_dp/3.0_dp)
     318           0 :       grad1 = INT(FLOOR(g1/6.0_dp + 2.0_dp/g1 - 1.0_dp - 2.e-6_dp))
     319           0 :       ii = n - grad1*(grad1 + 1)*(grad1 + 2)/6
     320           0 :       grad = INT(FLOOR(0.5_dp*(SQRT(9.0_dp + 8.0_dp*ii) - 1.0_dp) - 1.e-6_dp))
     321           0 :       res(3) = ii - grad*(grad + 1)/2
     322           0 :       res(2) = grad - res(3)
     323           0 :       res(1) = grad1 - grad
     324           0 :    END FUNCTION
     325             : 
     326             : ! **************************************************************************************************
     327             : !> \brief the index of the result of the multiplication of the two monomials
     328             : !> \param ii ...
     329             : !> \param ij ...
     330             : !> \return ...
     331             : ! **************************************************************************************************
     332           0 :    PURE FUNCTION mono_mult1(ii, ij) RESULT(res)
     333             :       INTEGER, INTENT(in)                                :: ii, ij
     334             :       INTEGER                                            :: res
     335             : 
     336           0 :       res = ii + ij
     337           0 :    END FUNCTION
     338             : 
     339             : ! **************************************************************************************************
     340             : !> \brief the index of the result of the multiplication of the two monomials
     341             : !> \param ii ...
     342             : !> \param ij ...
     343             : !> \return ...
     344             : ! **************************************************************************************************
     345           0 :    PURE FUNCTION mono_mult2(ii, ij) RESULT(res)
     346             :       INTEGER, INTENT(in)                                :: ii, ij
     347             :       INTEGER                                            :: res
     348             : 
     349             :       INTEGER, DIMENSION(2)                              :: monoRes
     350             : 
     351           0 :       monoRes = mono_exp2(ii) + mono_exp2(ij)
     352           0 :       res = mono_index2(monoRes(1), monoRes(2))
     353           0 :    END FUNCTION
     354             : 
     355             : ! **************************************************************************************************
     356             : !> \brief the index of the result of the multiplication of the two monomials
     357             : !> \param ii ...
     358             : !> \param ij ...
     359             : !> \return ...
     360             : ! **************************************************************************************************
     361           0 :    PURE FUNCTION mono_mult3(ii, ij) RESULT(res)
     362             :       INTEGER, INTENT(in)                                :: ii, ij
     363             :       INTEGER                                            :: res
     364             : 
     365             :       INTEGER, DIMENSION(3)                              :: monoRes
     366             : 
     367           0 :       monoRes = mono_exp3(ii) + mono_exp3(ij)
     368           0 :       res = mono_index3(monoRes(1), monoRes(2), monoRes(3))
     369           0 :    END FUNCTION
     370             : 
     371             : ! **************************************************************************************************
     372             : !> \brief multiplies the polynomials p1 with p2 using pRes to store the result
     373             : !> \param p1 ...
     374             : !> \param p2 ...
     375             : !> \param pRes ...
     376             : !> \param np1 ...
     377             : !> \param sumUp ...
     378             : ! **************************************************************************************************
     379           0 :    SUBROUTINE poly_mult1(p1, p2, pRes, np1, sumUp)
     380             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p1, p2
     381             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
     382             :       INTEGER, INTENT(in), OPTIONAL                      :: np1
     383             :       LOGICAL, INTENT(in), OPTIONAL                      :: sumUp
     384             : 
     385             :       INTEGER                                            :: i, ipoly, iPos, j, myNp1, newGrad, &
     386             :                                                             newSize, resPos, resShift_0, size_p1, &
     387             :                                                             size_p2
     388             :       LOGICAL                                            :: mySumUp
     389             : 
     390           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     391           0 :       mySumUp = .FALSE.
     392           0 :       myNp1 = 1
     393           0 :       IF (PRESENT(np1)) myNp1 = np1
     394           0 :       IF (PRESENT(sumUp)) mySumUp = sumUp
     395           0 :       size_p1 = SIZE(p1)/myNp1
     396           0 :       size_p2 = SIZE(p2)
     397           0 :       newGrad = grad_size1(size_p1) + grad_size1(size_p2)
     398           0 :       newSize = SIZE(pRes)/myNp1
     399           0 :       CPASSERT(newSize >= poly_size1(newGrad))
     400           0 :       IF (.NOT. mySumUp) pRes = 0
     401             :       iPos = 1
     402             :       resShift_0 = 0
     403           0 :       DO ipoly = 0, myNp1 - 1
     404           0 :          DO i = 1, size_p1
     405           0 :             resPos = resShift_0 + i
     406           0 :             DO j = 1, size_p2
     407           0 :                pRes(resPos) = pRes(resPos) + p1(iPos)*p2(j)
     408           0 :                resPos = resPos + 1
     409             :             END DO
     410           0 :             iPos = iPos + 1
     411             :          END DO
     412           0 :          resShift_0 = resShift_0 + newSize
     413             :       END DO
     414           0 :    END SUBROUTINE
     415             : 
     416             : ! **************************************************************************************************
     417             : !> \brief multiplies p1 with p2 using pRes to store the result
     418             : !> \param p1 ...
     419             : !> \param p2 ...
     420             : !> \param pRes ...
     421             : !> \param np1 ...
     422             : !> \param sumUp ...
     423             : ! **************************************************************************************************
     424           0 :    SUBROUTINE poly_mult2(p1, p2, pRes, np1, sumUp)
     425             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p1, p2
     426             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
     427             :       INTEGER, INTENT(in), OPTIONAL                      :: np1
     428             :       LOGICAL, INTENT(in), OPTIONAL                      :: sumUp
     429             : 
     430             :       INTEGER :: g1, g1g2, g2, grad1, grad2, i, ipoly, iShift, j, msize_p1, myNp1, newGrad, &
     431             :          newSize, shift1, shift2, shiftRes, shiftRes_0, size_p1, size_p2, subG2
     432             :       LOGICAL                                            :: mySumUp
     433             : 
     434           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     435           0 :       mySumUp = .FALSE.
     436           0 :       IF (PRESENT(sumUp)) mySumUp = sumUp
     437           0 :       myNp1 = 1
     438           0 :       IF (PRESENT(np1)) myNp1 = np1
     439           0 :       size_p1 = SIZE(p1)/myNp1
     440           0 :       size_p2 = SIZE(p2)
     441           0 :       grad1 = grad_size2(size_p1)
     442           0 :       grad2 = grad_size2(size_p2)
     443           0 :       newGrad = grad1 + grad2
     444           0 :       newSize = SIZE(pRes)/myNp1
     445           0 :       CPASSERT(newSize >= poly_size2(newGrad))
     446           0 :       IF (.NOT. mySumUp) pRes = 0
     447             :       iShift = 0
     448             :       shiftRes = 0
     449           0 :       DO ipoly = 1, myNp1
     450           0 :          DO i = 1, MIN(size_p1, cached_dim2)
     451           0 :             DO j = 1, MIN(size_p2, cached_dim2)
     452             :                pRes(shiftRes + a_mono_mult2(j, i)) = pRes(shiftRes + a_mono_mult2(j, i)) &
     453           0 :                                                      + p1(iShift + i)*p2(j)
     454             :             END DO
     455             :          END DO
     456           0 :          iShift = iShift + size_p1
     457           0 :          shiftRes = shiftRes + newSize
     458             :       END DO
     459           0 :       IF (grad1 > max_grad2 .OR. grad2 > max_grad2) THEN
     460             :          msize_p1 = size_p1
     461             :          shiftRes_0 = 0
     462           0 :          DO ipoly = 0, myNp1 - 1
     463           0 :             shift1 = ipoly*size_p1
     464           0 :             DO g1 = 0, grad1
     465             :                ! shift1=g1*(g1+1)/2
     466           0 :                IF (g1 > max_grad2) THEN
     467           0 :                   subG2 = 0
     468           0 :                   shift2 = 0
     469           0 :                   g1g2 = shiftRes_0 - 1
     470             :                ELSE
     471           0 :                   subG2 = max_grad2 + 1
     472           0 :                   shift2 = cached_dim2
     473           0 :                   g1g2 = shiftRes_0 + g1*subG2 - 1
     474             :                END IF
     475           0 :                DO g2 = subG2, grad2
     476             :                   ! shift2=g2*(g2+1)/2
     477           0 :                   shiftRes = shift1 + shift2 + g1g2 ! shiftRes=(g1+g2)*(g1+g2+1)/2-1+ipoly*newSize
     478           0 :                   DO i = 1, MIN(g1 + 1, msize_p1 - shift1)
     479           0 :                      DO j = 1, MIN(g2 + 1, size_p2 - shift2)
     480           0 :                         pRes(shiftRes + i + j) = pRes(shiftRes + i + j) + p1(shift1 + i)*p2(shift2 + j)
     481             :                      END DO
     482             :                   END DO
     483           0 :                   shift2 = shift2 + g2 + 1 !
     484           0 :                   g1g2 = g1g2 + g1 !
     485             :                END DO
     486           0 :                shift1 = shift1 + g1 + 1 !
     487             :             END DO
     488           0 :             shiftRes_0 = shiftRes_0 + newSize - size_p1
     489           0 :             msize_p1 = msize_p1 + size_p1
     490             :          END DO
     491             :       END IF
     492           0 :    END SUBROUTINE
     493             : 
     494             : ! **************************************************************************************************
     495             : !> \brief multiplies p1 with p2 using pRes to store the result
     496             : !> \param p1 ...
     497             : !> \param p2 ...
     498             : !> \param pRes ...
     499             : !> \param np1 ...
     500             : !> \param sumUp ...
     501             : ! **************************************************************************************************
     502           0 :    SUBROUTINE poly_mult3(p1, p2, pRes, np1, sumUp)
     503             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p1, p2
     504             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
     505             :       INTEGER, INTENT(in), OPTIONAL                      :: np1
     506             :       LOGICAL, INTENT(in), OPTIONAL                      :: sumUp
     507             : 
     508             :       INTEGER                                            :: grad1, grad2, myNp1, newGrad, newSize, &
     509             :                                                             size_p1, size_p2
     510             :       LOGICAL                                            :: mySumUp
     511             : 
     512           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     513           0 :       mySumUp = .FALSE.
     514           0 :       IF (PRESENT(sumUp)) mySumUp = sumUp
     515           0 :       myNp1 = 1
     516           0 :       IF (PRESENT(np1)) myNp1 = np1
     517           0 :       size_p1 = SIZE(p1)/myNp1
     518           0 :       size_p2 = SIZE(p2)
     519           0 :       grad1 = grad_size3(size_p1)
     520           0 :       grad2 = grad_size3(size_p2)
     521           0 :       newGrad = grad1 + grad2
     522           0 :       newSize = SIZE(pRes)/myNp1
     523           0 :       CPASSERT(newSize >= poly_size3(newGrad))
     524           0 :       CALL poly_mult3b(p1, SIZE(p1), grad1, p2, SIZE(p2), grad2, pRes, SIZE(pRes), myNp1, mySumUp)
     525           0 :    END SUBROUTINE
     526             : 
     527             : ! **************************************************************************************************
     528             : !> \brief low level routine of poly_mult3 without checks
     529             : !> \param p1 ...
     530             : !> \param size_p1 ...
     531             : !> \param grad1 ...
     532             : !> \param p2 ...
     533             : !> \param size_p2 ...
     534             : !> \param grad2 ...
     535             : !> \param pRes ...
     536             : !> \param size_pRes ...
     537             : !> \param np1 ...
     538             : !> \param sumUp ...
     539             : ! **************************************************************************************************
     540           0 :    SUBROUTINE poly_mult3b(p1, size_p1, grad1, p2, size_p2, grad2, pRes, size_pRes, np1, sumUp)
     541             :       INTEGER, INTENT(in)                                :: size_p1
     542             :       REAL(dp), DIMENSION(IF_CHECK(size_p1, *)), &
     543             :          INTENT(in)                                      :: p1
     544             :       INTEGER, INTENT(in)                                :: grad1, size_p2
     545             :       REAL(dp), DIMENSION(IF_CHECK(size_p2, *)), &
     546             :          INTENT(in)                                      :: p2
     547             :       INTEGER, INTENT(in)                                :: grad2, size_pRes
     548             :       REAL(dp), DIMENSION(IF_CHECK(size_pRes, *)), &
     549             :          INTENT(inout)                                   :: pRes
     550             :       INTEGER, INTENT(in)                                :: np1
     551             :       LOGICAL, INTENT(in)                                :: sumUp
     552             : 
     553             :       INTEGER :: g1, g2, i, i1, i2, ipoly, iShift, j, j1, j2, msize_p1, my_size_p1, newSize, &
     554             :          shift1, shift1I, shift1J, shift2, shift2I, shift2J, shiftRes, shiftRes_0, shiftResI, &
     555             :          shiftResI_0, shiftResJ, subG2, subGrad
     556             : 
     557           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     558           0 :       my_size_p1 = size_p1/np1
     559           0 :       newSize = size_pRes/np1
     560             : 
     561           0 :       IF (.NOT. sumUp) pRes(1:size_pRes) = 0.0_dp
     562             :       iShift = 0
     563             :       shiftRes = 0
     564           0 :       DO ipoly = 1, np1
     565           0 :          DO i = 1, MIN(my_size_p1, cached_dim3)
     566           0 :             DO j = 1, MIN(size_p2, cached_dim3)
     567             :                pRes(shiftRes + a_mono_mult3(j, i)) = pRes(shiftRes + a_mono_mult3(j, i)) &
     568           0 :                                                      + p1(iShift + i)*p2(j)
     569             :             END DO
     570             :          END DO
     571           0 :          iShift = iShift + my_size_p1
     572           0 :          shiftRes = shiftRes + newSize
     573             :       END DO
     574           0 :       IF (grad1 > max_grad3 .OR. grad2 > max_grad3) THEN
     575             :          ! one could remove multiplications even more aggressively...
     576             :          msize_p1 = my_size_p1
     577           0 :          DO ipoly = 0, np1 - 1
     578           0 :             shift1 = 1 + ipoly*my_size_p1
     579           0 :             shiftRes_0 = 1 + ipoly*newSize
     580           0 :             DO g1 = 0, grad1
     581           0 :                IF (g1 > max_grad3) THEN
     582             :                   subG2 = 0
     583             :                   shift2 = 1
     584             :                ELSE
     585           0 :                   subG2 = max_grad3 + 1
     586           0 :                   shift2 = subG2*(subG2 + 1)*(subG2 + 2)/6 + 1
     587             :                END IF
     588           0 :                DO g2 = subG2, grad2
     589           0 :                   shiftRes = (g1 + g2)*(g1 + g2 + 1)*(g1 + g2 + 2)/6 + shiftRes_0
     590           0 :                   shift1I = shift1
     591           0 :                   shiftResI_0 = shiftRes
     592           0 :                   DO i1 = g1, 0, -1
     593           0 :                      IF (shift1I > msize_p1) EXIT
     594           0 :                      shift2I = shift2
     595           0 :                      shiftResI = shiftResI_0
     596           0 :                      subGrad = g1 - i1
     597           0 :                      DO i2 = g2, 0, -1
     598             :                         !subGrad=g1+g2-i1-i2
     599             :                         !shiftResI=shiftRes+(subGrad)*(subGrad+1)/2
     600             :                         !shift2I=shift2+(g2-i2)*(g2-i2+1)/2
     601           0 :                         IF (shift2I > size_p2) EXIT
     602           0 :                         DO j1 = g1 - i1, 0, -1
     603           0 :                            shift1J = shift1I + g1 - i1 - j1
     604           0 :                            IF (shift1J > msize_p1) EXIT
     605           0 :                            DO j2 = g2 - i2, 0, -1
     606           0 :                               shift2J = shift2I + g2 - i2 - j2
     607           0 :                               IF (shift2J > size_p2) EXIT
     608           0 :                               shiftResJ = shiftResI + (subGrad - j1 - j2)
     609             :                               ! shift1J=mono_index3(i1,j1,g1-i1-j1)+ipoly*my_size_p1+1
     610             :                               ! shift2J=mono_index3(i2,j2,g2-i2-j2)+1
     611             :                               ! shiftResJ=mono_index3(i1+i2,j1+j2,g1+g2-i1-i2-j1-j2)+ipoly*newSize+1
     612           0 :                               pRes(shiftResJ) = pRes(shiftResJ) + p1(shift1J)*p2(shift2J)
     613             :                            END DO
     614             :                         END DO
     615           0 :                         subGrad = subGrad + 1
     616           0 :                         shift2I = shift2I + (g2 - i2 + 1)
     617           0 :                         shiftResI = shiftResI + subGrad
     618             :                      END DO
     619           0 :                      shift1I = shift1I + (g1 - i1 + 1)
     620           0 :                      shiftResI_0 = shiftResI_0 + (g1 - i1 + 1)
     621             :                   END DO
     622           0 :                   shift2 = shift2 + (g2 + 1)*(g2 + 2)/2
     623             :                END DO
     624           0 :                shift1 = shift1 + (g1 + 1)*(g1 + 2)/2
     625             :             END DO
     626           0 :             msize_p1 = msize_p1 + my_size_p1
     627             :          END DO
     628             :       END IF
     629           0 :    END SUBROUTINE
     630             : 
     631             : ! **************************************************************************************************
     632             : !> \brief low level routine that multiplies with a polynomial of grad 1
     633             : !> \param p1 ...
     634             : !> \param size_p1 ...
     635             : !> \param grad1 ...
     636             : !> \param p2 ...
     637             : !> \param pRes ...
     638             : !> \param size_pRes ...
     639             : !> \param np1 ...
     640             : !> \param sumUp ...
     641             : ! **************************************************************************************************
     642           0 :    SUBROUTINE poly_mult3ab(p1, size_p1, grad1, p2, pRes, size_pRes, np1, sumUp)
     643             :       INTEGER, INTENT(in)                                :: size_p1
     644             :       REAL(dp), DIMENSION(IF_CHECK(size_p1, *)), &
     645             :          INTENT(in)                                      :: p1
     646             :       INTEGER, INTENT(in)                                :: grad1
     647             :       REAL(dp), DIMENSION(IF_CHECK(4, *)), INTENT(in)    :: p2
     648             :       INTEGER, INTENT(in)                                :: size_pRes
     649             :       REAL(dp), DIMENSION(IF_CHECK(size_pRes, *)), &
     650             :          INTENT(inout)                                   :: pRes
     651             :       INTEGER, INTENT(in)                                :: np1
     652             :       LOGICAL, INTENT(in)                                :: sumUp
     653             : 
     654             :       INTEGER, PARAMETER                                 :: grad2 = 1
     655             : 
     656             :       INTEGER :: g1, g2, i, i1, i2, ipoly, iShift, j1, j2, msize_p1, my_size_p1, newSize, shift1, &
     657             :          shift1I, shift1J, shift2, shift2I, shift2J, shiftRes, shiftRes_0, shiftResI, shiftResI_0, &
     658             :          shiftResJ, subG2, subGrad
     659             : 
     660           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     661           0 :       my_size_p1 = size_p1/np1
     662           0 :       newSize = size_pRes/np1
     663             : 
     664           0 :       IF (.NOT. sumUp) pRes(1:size_pRes) = 0.0_dp
     665             :       iShift = 0
     666             :       shiftRes = 0
     667           0 :       DO ipoly = 1, np1
     668           0 :          DO i = 1, MIN(my_size_p1, cached_dim3)
     669             :             pRes(shiftRes + a_mono_mult3a(1, i)) = pRes(shiftRes + a_mono_mult3a(1, i)) &
     670           0 :                                                    + p1(iShift + i)*p2(1)
     671             :             pRes(shiftRes + a_mono_mult3a(2, i)) = pRes(shiftRes + a_mono_mult3a(2, i)) &
     672           0 :                                                    + p1(iShift + i)*p2(2)
     673             :             pRes(shiftRes + a_mono_mult3a(3, i)) = pRes(shiftRes + a_mono_mult3a(3, i)) &
     674           0 :                                                    + p1(iShift + i)*p2(3)
     675             :             pRes(shiftRes + a_mono_mult3a(4, i)) = pRes(shiftRes + a_mono_mult3a(4, i)) &
     676           0 :                                                    + p1(iShift + i)*p2(4)
     677             :          END DO
     678           0 :          iShift = iShift + my_size_p1
     679           0 :          shiftRes = shiftRes + newSize
     680             :       END DO
     681           0 :       IF (grad1 > max_grad3 .OR. grad2 > max_grad3) THEN
     682             :          ! one could remove multiplications even more aggressively...
     683             :          msize_p1 = my_size_p1
     684           0 :          DO ipoly = 0, np1 - 1
     685           0 :             shift1 = 1 + ipoly*my_size_p1 + (max_grad3 + 1)*(max_grad3 + 2)*(max_grad3 + 3)/6
     686           0 :             shiftRes_0 = 1 + ipoly*newSize
     687           0 :             DO g1 = max_grad3 + 1, grad1
     688             :                subG2 = 0
     689             :                shift2 = 1
     690           0 :                DO g2 = subG2, grad2
     691           0 :                   shiftRes = (g1 + g2)*(g1 + g2 + 1)*(g1 + g2 + 2)/6 + shiftRes_0
     692           0 :                   shift1I = shift1
     693           0 :                   shiftResI_0 = shiftRes
     694           0 :                   DO i1 = g1, 0, -1
     695           0 :                      IF (shift1I > msize_p1) EXIT
     696           0 :                      shift2I = shift2
     697           0 :                      shiftResI = shiftResI_0
     698           0 :                      subGrad = g1 - i1
     699           0 :                      DO i2 = g2, 0, -1
     700             :                         !subGrad=g1+g2-i1-i2
     701             :                         !shiftResI=shiftRes+(subGrad)*(subGrad+1)/2
     702             :                         !shift2I=shift2+(g2-i2)*(g2-i2+1)/2
     703           0 :                         DO j1 = g1 - i1, 0, -1
     704           0 :                            shift1J = shift1I + g1 - i1 - j1
     705           0 :                            IF (shift1J > msize_p1) EXIT
     706           0 :                            DO j2 = g2 - i2, 0, -1
     707           0 :                               shift2J = shift2I + g2 - i2 - j2
     708           0 :                               shiftResJ = shiftResI + (subGrad - j1 - j2)
     709             :                               ! shift1J=mono_index3(i1,j1,g1-i1-j1)+ipoly*my_size_p1+1
     710             :                               ! shift2J=mono_index3(i2,j2,g2-i2-j2)+1
     711             :                               ! shiftResJ=mono_index3(i1+i2,j1+j2,g1+g2-i1-i2-j1-j2)+ipoly*newSize+1
     712           0 :                               pRes(shiftResJ) = pRes(shiftResJ) + p1(shift1J)*p2(shift2J)
     713             :                            END DO
     714             :                         END DO
     715           0 :                         subGrad = subGrad + 1
     716           0 :                         shift2I = shift2I + (g2 - i2 + 1)
     717           0 :                         shiftResI = shiftResI + subGrad
     718             :                      END DO
     719           0 :                      shift1I = shift1I + (g1 - i1 + 1)
     720           0 :                      shiftResI_0 = shiftResI_0 + (g1 - i1 + 1)
     721             :                   END DO
     722           0 :                   shift2 = shift2 + (g2 + 1)*(g2 + 2)/2
     723             :                END DO
     724           0 :                shift1 = shift1 + (g1 + 1)*(g1 + 2)/2
     725             :             END DO
     726           0 :             msize_p1 = msize_p1 + my_size_p1
     727             :          END DO
     728             :       END IF
     729           0 :    END SUBROUTINE
     730             : 
     731             : ! **************************************************************************************************
     732             : !> \brief writes out a 1d polynomial in a human readable form
     733             : !> \param p ...
     734             : !> \param out_f ...
     735             : ! **************************************************************************************************
     736           0 :    SUBROUTINE poly_write1(p, out_f)
     737             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
     738             :       INTEGER, INTENT(in)                                :: out_f
     739             : 
     740             :       INTEGER                                            :: i
     741             :       LOGICAL                                            :: did_write
     742             : 
     743           0 :       did_write = .FALSE.
     744           0 :       DO i = 1, SIZE(p)
     745           0 :          IF (p(i) /= 0) THEN
     746           0 :             IF (p(i) >= 0) WRITE (out_f, '("+")', advance='NO')
     747           0 :             WRITE (out_f, '(G20.10)', advance='NO') p(i)
     748           0 :             IF (i /= 1) WRITE (out_f, '("*x^",I3)', advance='NO') i - 1
     749             :             did_write = .TRUE.
     750             :          END IF
     751             :       END DO
     752           0 :       IF (.NOT. did_write) WRITE (out_f, '("0.0")', advance='NO')
     753           0 :    END SUBROUTINE
     754             : 
     755             : ! **************************************************************************************************
     756             : !> \brief writes out a 2d polynomial in a human readable form
     757             : !> \param p ...
     758             : !> \param out_f ...
     759             : ! **************************************************************************************************
     760           0 :    SUBROUTINE poly_write2(p, out_f)
     761             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
     762             :       INTEGER, INTENT(in)                                :: out_f
     763             : 
     764             :       INTEGER                                            :: i
     765             :       INTEGER, DIMENSION(2)                              :: mono_e
     766             :       LOGICAL                                            :: did_write
     767             : 
     768           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     769           0 :       did_write = .FALSE.
     770           0 :       DO i = 1, SIZE(p)
     771           0 :          mono_e = mono_exp2(i - 1)
     772           0 :          IF (p(i) /= 0) THEN
     773           0 :             IF (p(i) >= 0) WRITE (out_f, '("+")', advance='NO')
     774           0 :             WRITE (out_f, '(G20.10)', advance='NO') p(i)
     775           0 :             IF (mono_e(1) /= 0) WRITE (out_f, '("*x^",I3)', advance='NO') mono_e(1)
     776           0 :             IF (mono_e(2) /= 0) WRITE (out_f, '("*y^",I3)', advance='NO') mono_e(2)
     777             :             did_write = .TRUE.
     778             :          END IF
     779             :       END DO
     780           0 :       IF (.NOT. did_write) WRITE (out_f, '("0.0")', advance='NO')
     781           0 :    END SUBROUTINE
     782             : 
     783             : ! **************************************************************************************************
     784             : !> \brief writes out the polynomial in a human readable form
     785             : !> \param p ...
     786             : !> \param out_f ...
     787             : ! **************************************************************************************************
     788           0 :    SUBROUTINE poly_write3(p, out_f)
     789             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
     790             :       INTEGER, INTENT(in)                                :: out_f
     791             : 
     792             :       INTEGER                                            :: i
     793             :       INTEGER, DIMENSION(3)                              :: mono_e
     794             :       LOGICAL                                            :: did_write
     795             : 
     796           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     797           0 :       did_write = .FALSE.
     798           0 :       DO i = 1, SIZE(p)
     799           0 :          mono_e = mono_exp3(i - 1)
     800           0 :          IF (p(i) /= 0) THEN
     801           0 :             IF (p(i) >= 0) WRITE (out_f, '("+")', advance='NO')
     802           0 :             WRITE (out_f, '(G20.10)', advance='NO') p(i)
     803           0 :             IF (mono_e(1) /= 0) WRITE (out_f, '("*x^",I3)', advance='NO') mono_e(1)
     804           0 :             IF (mono_e(2) /= 0) WRITE (out_f, '("*y^",I3)', advance='NO') mono_e(2)
     805           0 :             IF (mono_e(3) /= 0) WRITE (out_f, '("*z^",I3)', advance='NO') mono_e(3)
     806             :             did_write = .TRUE.
     807             :          END IF
     808             :       END DO
     809           0 :       IF (.NOT. did_write) WRITE (out_f, '("0.0")', advance='NO')
     810           0 :    END SUBROUTINE
     811             : 
     812             : ! **************************************************************************************************
     813             : !> \brief random poly with coeffiecents that are easy to print exactly,
     814             : !>        of the given maximum size (for testing purposes)
     815             : !> \param p ...
     816             : !> \param maxSize ...
     817             : !> \param minSize ...
     818             : !> \return ...
     819             : ! **************************************************************************************************
     820           0 :    FUNCTION poly_random(p, maxSize, minSize) RESULT(res)
     821             :       REAL(dp), DIMENSION(:), INTENT(out)                :: p
     822             :       INTEGER, INTENT(in)                                :: maxSize
     823             :       INTEGER, INTENT(in), OPTIONAL                      :: minSize
     824             :       INTEGER                                            :: res
     825             : 
     826             :       INTEGER                                            :: i, myMinSize, pSize
     827             :       REAL(dp)                                           :: g
     828             : 
     829           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     830           0 :       myMinSize = 1
     831           0 :       IF (PRESENT(minSize)) myMinSize = minSize
     832           0 :       CALL RANDOM_NUMBER(g)
     833           0 :       pSize = MIN(maxSize, myMinSize + INT((maxSize - myMinSize + 1)*g))
     834           0 :       CPASSERT(SIZE(p) >= pSize)
     835           0 :       CALL RANDOM_NUMBER(p)
     836           0 :       DO i = 1, pSize
     837           0 :          p(i) = REAL(INT(p(i)*200.0_dp - 100.0_dp), dp)/100.0_dp
     838             :       END DO
     839           0 :       DO i = pSize + 1, SIZE(p)
     840           0 :          p(i) = 0.0_dp
     841             :       END DO
     842           0 :       res = pSize
     843           0 :    END FUNCTION
     844             : 
     845             : ! **************************************************************************************************
     846             : !> \brief returns in the polynomials pRes the transpose of the
     847             : !> affine transformation x -> m*x+b of p
     848             : !> \param p ...
     849             : !> \param m ...
     850             : !> \param b ...
     851             : !> \param pRes ...
     852             : !> \param npoly ...
     853             : ! **************************************************************************************************
     854           0 :    SUBROUTINE poly_affine_t3t(p, m, b, pRes, npoly)
     855             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
     856             :       REAL(dp), DIMENSION(3, 3), INTENT(in)              :: m
     857             :       REAL(dp), DIMENSION(3), INTENT(in)                 :: b
     858             :       REAL(dp), DIMENSION(:), INTENT(out)                :: pRes
     859             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
     860             : 
     861             :       INTEGER :: grad, i, igrad, ii, ii1, ipoly, j, k, minResSize, monoDim1, monoDim2, monoDimAtt, &
     862             :          monoDimAtt2, monoFullDim1, monoFullDim2, monoSize1, monoSize2, my_npoly, pcoeff, pIdx, &
     863             :          pShift, rescoeff, resShift, rest_size_p, size_p, size_res, start_idx1
     864           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: monoG1, monoG2
     865             :       REAL(dp), DIMENSION(4, 3)                          :: basepoly
     866             : 
     867           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
     868           0 :       my_npoly = 1
     869           0 :       IF (PRESENT(npoly)) my_npoly = npoly
     870           0 :       basepoly(1, :) = b
     871           0 :       DO j = 1, 3
     872           0 :          DO i = 1, 3
     873           0 :             basepoly(j + 1, i) = m(i, j)
     874             :          END DO
     875             :       END DO
     876           0 :       size_p = SIZE(pRes)/my_npoly
     877           0 :       size_res = SIZE(p)/my_npoly
     878           0 :       grad = grad_size3(size_res)
     879           0 :       minResSize = poly_size3(grad)
     880           0 :       CPASSERT(size_res == minResSize)
     881           0 :       CPASSERT(size_p >= minResSize)
     882           0 :       pRes = 0
     883           0 :       IF (size_p == 0) RETURN
     884             :       ii1 = 1
     885             :       ii = 1
     886           0 :       DO ipoly = 1, my_npoly
     887           0 :          pRes(ii1) = p(ii)
     888           0 :          ii = ii + size_res
     889           0 :          ii1 = ii1 + size_p
     890             :       END DO
     891           0 :       IF (size_p == 1) RETURN
     892             : 
     893             :       ALLOCATE (monoG1((grad + 1)*(grad + 2)/2*minResSize), &
     894           0 :                 monoG2((grad + 1)*(grad + 2)/2*minResSize))
     895             :       !monoG1=0
     896             :       !monoG2=0
     897           0 :       ii1 = 1
     898           0 :       DO j = 1, 3
     899           0 :          DO i = 1, 4
     900           0 :             monoG1(ii1) = basepoly(i, j)
     901           0 :             ii1 = ii1 + 1
     902             :          END DO
     903             :       END DO
     904           0 :       ii1 = 2
     905           0 :       igrad = 1
     906           0 :       monoDim1 = 4
     907           0 :       monoSize1 = 3
     908           0 :       monoFullDim1 = monoDim1*monoSize1
     909           0 :       rest_size_p = size_p - 1
     910           0 :       DO
     911           0 :          k = MIN(rest_size_p, monoSize1)
     912             :          !call dgemm('T','N',monoDim1,my_npoly,k,&
     913             :          !    1.0_dp,monoG1,monoDim1,p(ii1:),size_p,1.0_dp,pRes,size_res)
     914           0 :          resShift = 0
     915           0 :          pShift = ii1
     916           0 :          DO ipoly = 1, my_npoly
     917             :             pIdx = pShift
     918             :             ii = 1
     919           0 :             DO pcoeff = 1, k
     920           0 :                DO rescoeff = 1, monoDim1
     921           0 :                   pRes(pIdx) = pRes(pIdx) + p(resShift + rescoeff)*monoG1(ii)
     922           0 :                   ii = ii + 1
     923             :                END DO
     924           0 :                pIdx = pIdx + 1
     925             :             END DO
     926           0 :             resShift = resShift + size_res
     927           0 :             pShift = pShift + size_p
     928             :          END DO
     929             : 
     930           0 :          rest_size_p = rest_size_p - k
     931           0 :          ii1 = ii1 + k
     932           0 :          IF (rest_size_p <= 0) EXIT
     933             : 
     934           0 :          monoSize2 = igrad + 2 + monoSize1
     935           0 :          monoDim2 = monoDim1 + monoSize2
     936           0 :          monoFullDim2 = monoSize2*monoDim2
     937           0 :          monoDimAtt = monoSize1*monoDim2
     938             :          CALL poly_mult3ab(IF_CHECK(monoG1(1:monoFullDim1), monoG1(1)), monoFullDim1, igrad, &
     939             :                            IF_CHECK(basepoly(:, 1), basepoly(1, 1)), &
     940           0 :                            IF_CHECK(monoG2(1:monoDimAtt), monoG2(1)), monoDimAtt, monoSize1, .FALSE.)
     941           0 :          monoDimAtt2 = monoFullDim2 - monoDim2
     942           0 :          start_idx1 = (monoSize1 - igrad - 1)*monoDim1
     943             :          CALL poly_mult3ab(IF_CHECK(monoG1(start_idx1 + 1:monoFullDim1), monoG1(start_idx1 + 1)), &
     944             :                            monoFullDim1 - start_idx1, igrad, IF_CHECK(basepoly(:, 2), basepoly(1, 2)), &
     945             :                            IF_CHECK(monoG2(monoDimAtt + 1:monoDimAtt2), monoG2(monoDimAtt + 1)), &
     946           0 :                            monoDimAtt2 - monoDimAtt, igrad + 1, .FALSE.)
     947             :          CALL poly_mult3ab(IF_CHECK(monoG1(monoFullDim1 - monoDim1 + 1:monoFullDim1), monoG1(monoFullDim1 - monoDim1 + 1)), &
     948             :                            monoDim1, igrad, IF_CHECK(basepoly(:, 3), basepoly(1, 3)), &
     949             :                            IF_CHECK(monoG2(monoDimAtt2 + 1:monoFullDim2), monoG2(monoDimAtt2 + 1)), &
     950           0 :                            monoFullDim2 - monoDimAtt2, 1, .FALSE.)
     951           0 :          igrad = igrad + 1
     952             : 
     953             :          ! even grads
     954             : 
     955           0 :          k = MIN(rest_size_p, monoSize2)
     956             :          !call dgemm('T','N',monoDim2,my_npoly,k,&
     957             :          !    1.0_dp,monoG2,monoDim2,p(ii1:),size_p,1.0_dp,pRes,size_res)
     958           0 :          resShift = 0
     959           0 :          pShift = ii1
     960           0 :          DO ipoly = 1, my_npoly
     961             :             pIdx = pShift
     962             :             ii = 1
     963           0 :             DO pcoeff = 1, k
     964           0 :                DO rescoeff = 1, monoDim2
     965           0 :                   pRes(pIdx) = pRes(pIdx) + p(resShift + rescoeff)*monoG2(ii)
     966           0 :                   ii = ii + 1
     967             :                END DO
     968           0 :                pIdx = pIdx + 1
     969             :             END DO
     970           0 :             resShift = resShift + size_res
     971           0 :             pShift = pShift + size_p
     972             :          END DO
     973             : 
     974           0 :          rest_size_p = rest_size_p - k
     975           0 :          ii1 = ii1 + k
     976           0 :          IF (rest_size_p <= 0) EXIT
     977             : 
     978           0 :          monoSize1 = igrad + 2 + monoSize2
     979           0 :          monoDim1 = monoDim2 + monoSize1
     980           0 :          monoFullDim1 = monoSize1*monoDim1
     981           0 :          monoDimAtt = monoSize2*monoDim1
     982             :          CALL poly_mult3ab(IF_CHECK(monoG2(1:monoFullDim2), monoG2(1)), monoFullDim2, igrad, &
     983             :                            IF_CHECK(basepoly(:, 1), basepoly(1, 1)), IF_CHECK(monoG1(1:monoDimAtt), monoG1(1)), &
     984           0 :                            monoDimAtt, monoSize2, .FALSE.)
     985           0 :          monoDimAtt2 = monoFullDim1 - monoDim1
     986           0 :          start_idx1 = (monoSize2 - igrad - 1)*monoDim2
     987             :          CALL poly_mult3ab(IF_CHECK(monoG2(start_idx1 + 1:monoFullDim2), monoG2(start_idx1 + 1)), &
     988             :                            monoFullDim2 - start_idx1, igrad, IF_CHECK(basepoly(:, 2), basepoly(1, 2)), &
     989             :                            IF_CHECK(monoG1(monoDimAtt + 1:monoDimAtt2), monoG1(monoDimAtt + 1)), monoDimAtt2 - monoDimAtt, &
     990           0 :                            igrad + 1, .FALSE.)
     991             :          CALL poly_mult3ab(IF_CHECK(monoG2(monoFullDim2 - monoDim2 + 1:monoFullDim2), monoG2(monoFullDim2 - monoDim2 + 1)), &
     992             :                            monoDim2, igrad, IF_CHECK(basepoly(:, 3), basepoly(1, 3)), &
     993             :                            IF_CHECK(monoG1(monoDimAtt2 + 1:monoFullDim1), monoG1(monoDimAtt2 + 1)), &
     994           0 :                            monoFullDim1 - monoDimAtt2, 1, .FALSE.)
     995           0 :          igrad = igrad + 1
     996             : 
     997             :          ! ! alternative to unrolling
     998             :          ! monoG1=monoG2
     999             :          ! monoSize1=monoSize2
    1000             :          ! monoDim1=monoDim2
    1001             :          ! monoFullDim1=monoFullDim2
    1002             :       END DO
    1003           0 :       DEALLOCATE (monoG1, monoG2)
    1004             :    END SUBROUTINE
    1005             : 
    1006             : ! **************************************************************************************************
    1007             : !> \brief returns in the polynomials pRes the affine transformation x -> m*x+b of p
    1008             : !> \param p ...
    1009             : !> \param m ...
    1010             : !> \param b ...
    1011             : !> \param pRes ...
    1012             : !> \param npoly ...
    1013             : ! **************************************************************************************************
    1014           0 :    SUBROUTINE poly_affine_t3(p, m, b, pRes, npoly)
    1015             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
    1016             :       REAL(dp), DIMENSION(3, 3), INTENT(in)              :: m
    1017             :       REAL(dp), DIMENSION(3), INTENT(in)                 :: b
    1018             :       REAL(dp), DIMENSION(:), INTENT(out)                :: pRes
    1019             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1020             : 
    1021             :       INTEGER :: grad, i, igrad, ii, ii1, ipoly, j, k, minResSize, monoDim1, monoDim2, monoDimAtt, &
    1022             :          monoDimAtt2, monoFullDim1, monoFullDim2, monoSize1, monoSize2, my_npoly, pcoeff, pIdx, &
    1023             :          pShift, rescoeff, resShift, rest_size_p, size_p, size_res, start_idx1
    1024           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: monoG1, monoG2
    1025             :       REAL(dp), DIMENSION(4, 3)                          :: basepoly
    1026             : 
    1027           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1028           0 :       my_npoly = 1
    1029           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1030           0 :       basepoly(1, :) = b
    1031           0 :       DO j = 1, 3
    1032           0 :          DO i = 1, 3
    1033           0 :             basepoly(j + 1, i) = m(i, j)
    1034             :          END DO
    1035             :       END DO
    1036           0 :       size_p = SIZE(p)/my_npoly
    1037           0 :       grad = grad_size3(size_p)
    1038           0 :       size_res = SIZE(pRes)/my_npoly
    1039           0 :       minResSize = poly_size3(grad)
    1040           0 :       CPASSERT(size_res >= minResSize)
    1041           0 :       pRes = 0
    1042           0 :       IF (size_p == 0) RETURN
    1043             :       ii1 = 1
    1044             :       ii = 1
    1045           0 :       DO ipoly = 1, my_npoly
    1046           0 :          pRes(ii) = p(ii1)
    1047           0 :          ii = ii + size_res
    1048           0 :          ii1 = ii1 + size_p
    1049             :       END DO
    1050           0 :       IF (size_p == 1) RETURN
    1051             : 
    1052             :       ALLOCATE (monoG1((grad + 1)*(grad + 2)/2*minResSize), &
    1053           0 :                 monoG2((grad + 1)*(grad + 2)/2*minResSize))
    1054           0 :       monoG1 = 0
    1055           0 :       monoG2 = 0
    1056             :       ii1 = 1
    1057           0 :       DO j = 1, 3
    1058           0 :          DO i = 1, 4
    1059           0 :             monoG1(ii1) = basepoly(i, j)
    1060           0 :             ii1 = ii1 + 1
    1061             :          END DO
    1062             :       END DO
    1063           0 :       ii1 = 2
    1064           0 :       igrad = 1
    1065           0 :       monoDim1 = 4
    1066           0 :       monoSize1 = 3
    1067           0 :       monoFullDim1 = monoDim1*monoSize1
    1068           0 :       rest_size_p = size_p - 1
    1069           0 :       DO
    1070           0 :          k = MIN(rest_size_p, monoSize1)
    1071             :          !call dgemm('T','N',monoDim1,my_npoly,k,&
    1072             :          !    1.0_dp,monoG1,monoDim1,p(ii1:),size_p,1.0_dp,pRes,size_res)
    1073           0 :          resShift = 0
    1074           0 :          pShift = ii1
    1075           0 :          DO ipoly = 1, my_npoly
    1076             :             pIdx = pShift
    1077             :             ii = 1
    1078           0 :             DO pcoeff = 1, k
    1079           0 :                DO rescoeff = 1, monoDim1
    1080           0 :                   pRes(resShift + rescoeff) = pRes(resShift + rescoeff) + p(pIdx)*monoG1(ii)
    1081           0 :                   ii = ii + 1
    1082             :                END DO
    1083           0 :                pIdx = pIdx + 1
    1084             :             END DO
    1085           0 :             resShift = resShift + size_res
    1086           0 :             pShift = pShift + size_p
    1087             :          END DO
    1088             : 
    1089           0 :          rest_size_p = rest_size_p - k
    1090           0 :          ii1 = ii1 + k
    1091           0 :          IF (rest_size_p <= 0) EXIT
    1092             : 
    1093           0 :          monoSize2 = igrad + 2 + monoSize1
    1094           0 :          monoDim2 = monoDim1 + monoSize2
    1095           0 :          monoFullDim2 = monoSize2*monoDim2
    1096           0 :          monoDimAtt = monoSize1*monoDim2
    1097             :          CALL poly_mult3ab(IF_CHECK(monoG1(1:monoFullDim1), monoG1(1)), monoFullDim1, igrad, &
    1098             :                            IF_CHECK(basepoly(:, 1), basepoly(1, 1)), &
    1099           0 :                            IF_CHECK(monoG2(1:monoDimAtt), monoG2(1)), monoDimAtt, monoSize1, .FALSE.)
    1100           0 :          monoDimAtt2 = monoFullDim2 - monoDim2
    1101           0 :          start_idx1 = (monoSize1 - igrad - 1)*monoDim1
    1102             :          CALL poly_mult3ab(IF_CHECK(monoG1(start_idx1 + 1:monoFullDim1), monoG1(start_idx1 + 1)), &
    1103             :                            monoFullDim1 - start_idx1, igrad, IF_CHECK(basepoly(:, 2), basepoly(1, 2)), &
    1104             :                            IF_CHECK(monoG2(monoDimAtt + 1:monoDimAtt2), monoG2(monoDimAtt + 1)), &
    1105           0 :                            monoDimAtt2 - monoDimAtt, igrad + 1, .FALSE.)
    1106             :          CALL poly_mult3ab(IF_CHECK(monoG1(monoFullDim1 - monoDim1 + 1:monoFullDim1), monoG1(monoFullDim1 - monoDim1 + 1)), &
    1107             :                            monoDim1, igrad, IF_CHECK(basepoly(:, 3), basepoly(1, 3)), &
    1108             :                            IF_CHECK(monoG2(monoDimAtt2 + 1:monoFullDim2), monoG2(monoDimAtt2 + 1)), &
    1109           0 :                            monoFullDim2 - monoDimAtt2, 1, .FALSE.)
    1110           0 :          igrad = igrad + 1
    1111             : 
    1112             :          ! even grads
    1113             : 
    1114           0 :          k = MIN(rest_size_p, monoSize2)
    1115             :          !call dgemm('T','N',monoDim2,my_npoly,k,&
    1116             :          !    1.0_dp,monoG2,monoDim2,p(ii1:),size_p,1.0_dp,pRes,size_res)
    1117           0 :          resShift = 0
    1118           0 :          pShift = ii1
    1119           0 :          DO ipoly = 1, my_npoly
    1120             :             pIdx = pShift
    1121             :             ii = 1
    1122           0 :             DO pcoeff = 1, k
    1123           0 :                DO rescoeff = 1, monoDim2
    1124           0 :                   pRes(resShift + rescoeff) = pRes(resShift + rescoeff) + p(pIdx)*monoG2(ii)
    1125           0 :                   ii = ii + 1
    1126             :                END DO
    1127           0 :                pIdx = pIdx + 1
    1128             :             END DO
    1129           0 :             resShift = resShift + size_res
    1130           0 :             pShift = pShift + size_p
    1131             :          END DO
    1132             : 
    1133           0 :          rest_size_p = rest_size_p - k
    1134           0 :          ii1 = ii1 + k
    1135           0 :          IF (rest_size_p <= 0) EXIT
    1136             : 
    1137           0 :          monoSize1 = igrad + 2 + monoSize2
    1138           0 :          monoDim1 = monoDim2 + monoSize1
    1139           0 :          monoFullDim1 = monoSize1*monoDim1
    1140           0 :          monoDimAtt = monoSize2*monoDim1
    1141             :          CALL poly_mult3ab(IF_CHECK(monoG2(1:monoFullDim2), monoG2(1)), monoFullDim2, igrad, &
    1142             :                            IF_CHECK(basepoly(:, 1), basepoly(1, 1)), &
    1143           0 :                            IF_CHECK(monoG1(1:monoDimAtt), monoG1(1)), monoDimAtt, monoSize2, .FALSE.)
    1144           0 :          monoDimAtt2 = monoFullDim1 - monoDim1
    1145           0 :          start_idx1 = (monoSize2 - igrad - 1)*monoDim2
    1146             :          CALL poly_mult3ab(IF_CHECK(monoG2(start_idx1 + 1:monoFullDim2), monoG2(start_idx1 + 1)), &
    1147             :                            monoFullDim2 - start_idx1, igrad, &
    1148             :                            IF_CHECK(basepoly(:, 2), basepoly(1, 2)), &
    1149             :                            IF_CHECK(monoG1(monoDimAtt + 1:monoDimAtt2), monoG1(monoDimAtt + 1)), monoDimAtt2 - monoDimAtt, &
    1150           0 :                            igrad + 1, .FALSE.)
    1151             :          CALL poly_mult3ab(IF_CHECK(monoG2(monoFullDim2 - monoDim2 + 1:monoFullDim2), monoG2(monoFullDim2 - monoDim2 + 1)), &
    1152             :                            monoDim2, igrad, IF_CHECK(basepoly(:, 3), basepoly(1, 3)), &
    1153             :                            IF_CHECK(monoG1(monoDimAtt2 + 1:monoFullDim1), monoG1(monoDimAtt2 + 1)), &
    1154           0 :                            monoFullDim1 - monoDimAtt2, 1, .FALSE.)
    1155           0 :          igrad = igrad + 1
    1156             : 
    1157             :          ! ! alternative to unrolling
    1158             :          ! monoG1=monoG2
    1159             :          ! monoSize1=monoSize2
    1160             :          ! monoDim1=monoDim2
    1161             :          ! monoFullDim1=monoFullDim2
    1162             :       END DO
    1163           0 :       DEALLOCATE (monoG1, monoG2)
    1164             :    END SUBROUTINE
    1165             : 
    1166             : ! **************************************************************************************************
    1167             : !> \brief evaluates the 3d polymial at x (the result is a polynomial in two variables)
    1168             : !> \param p ...
    1169             : !> \param x ...
    1170             : !> \param pRes ...
    1171             : !> \param npoly ...
    1172             : ! **************************************************************************************************
    1173           0 :    SUBROUTINE poly_p_eval3(p, x, pRes, npoly)
    1174             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
    1175             :       REAL(dp), INTENT(in)                               :: x
    1176             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
    1177             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1178             : 
    1179             :       INTEGER                                            :: grad, my_npoly, newSize, size_p
    1180           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: xi
    1181             : 
    1182           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1183           0 :       my_npoly = 1
    1184           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1185           0 :       size_p = SIZE(p)/my_npoly
    1186           0 :       grad = grad_size3(size_p)
    1187           0 :       newSize = SIZE(pRes)/my_npoly
    1188           0 :       CPASSERT(newSize >= poly_size2(grad))
    1189           0 :       pRes = 0.0
    1190           0 :       ALLOCATE (xi(grad + 1))
    1191           0 :       CALL poly_p_eval3b(p, SIZE(p), x, pRes, SIZE(pRes), my_npoly, grad, xi)
    1192           0 :       DEALLOCATE (xi)
    1193           0 :    END SUBROUTINE
    1194             : 
    1195             : ! **************************************************************************************************
    1196             : !> \brief low level routine of poly_p_eval3 without checks
    1197             : !> \param p ...
    1198             : !> \param size_p ...
    1199             : !> \param x ...
    1200             : !> \param pRes ...
    1201             : !> \param size_pRes ...
    1202             : !> \param npoly ...
    1203             : !> \param grad ...
    1204             : !> \param xi ...
    1205             : ! **************************************************************************************************
    1206           0 :    SUBROUTINE poly_p_eval3b(p, size_p, x, pRes, size_pRes, npoly, grad, xi)
    1207             :       INTEGER, INTENT(in)                                :: size_p
    1208             :       REAL(dp), DIMENSION(IF_CHECK(size_p, *)), &
    1209             :          INTENT(in)                                      :: p
    1210             :       REAL(dp), INTENT(in)                               :: x
    1211             :       INTEGER, INTENT(in)                                :: size_pRes
    1212             :       REAL(dp), DIMENSION(IF_CHECK(size_pRes, *)), &
    1213             :          INTENT(inout)                                   :: pRes
    1214             :       INTEGER, INTENT(in)                                :: npoly, grad
    1215             :       REAL(dp), DIMENSION(IF_CHECK(grad+1, *)), &
    1216             :          INTENT(inout)                                   :: xi
    1217             : 
    1218             :       INTEGER                                            :: i, igrad, ii, ii0, inSize, ipoly, j, &
    1219             :                                                             msize_p, newSize, pShift, shiftRes, &
    1220             :                                                             shiftRes_0, subG
    1221             : 
    1222           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1223           0 :       inSize = size_p/npoly
    1224           0 :       newSize = size_pRes/npoly
    1225           0 :       pRes(1:size_pRes) = 0.0
    1226           0 :       xi(1) = 1.0
    1227           0 :       DO i = 1, grad
    1228           0 :          xi(i + 1) = xi(i)*x
    1229             :       END DO
    1230             :       shiftRes = 0
    1231             :       pShift = 0
    1232           0 :       DO ipoly = 1, npoly
    1233           0 :          DO ii = 1, MIN(inSize, cached_dim3)
    1234           0 :             pRes(shiftRes + a_reduce_idx3(ii)) = pRes(shiftRes + a_reduce_idx3(ii)) + p(pShift + ii)*xi(a_mono_exp3(1, ii) + 1)
    1235             :          END DO
    1236           0 :          shiftRes = shiftRes + newSize
    1237           0 :          pShift = pShift + inSize
    1238             :       END DO
    1239           0 :       IF (grad > max_grad3) THEN
    1240             :          ii0 = (max_grad3 + 1)*(max_grad3 + 2)*(max_grad3 + 3)/6 + 1
    1241             :          shiftRes_0 = 1
    1242             :          msize_p = inSize
    1243           0 :          DO ipoly = 1, npoly
    1244             :             ii = ii0
    1245           0 :             grad_do: DO igrad = max_grad3 + 1, grad
    1246             :                !ii=igrad*(igrad+1)*(igrad+2)/6+1
    1247             :                shiftRes = shiftRes_0
    1248             :                subG = 0
    1249           0 :                DO i = igrad, 0, -1
    1250             :                   !subG=igrad-i
    1251             :                   !shiftRes=subG*(subG+3)/2+1
    1252           0 :                   DO j = subG, 0, -1
    1253           0 :                      IF (msize_p < ii) EXIT grad_do
    1254           0 :                      pRes(shiftRes - j) = pRes(shiftRes - j) + p(ii)*xi(i + 1)
    1255           0 :                      ii = ii + 1
    1256             :                   END DO
    1257           0 :                   shiftRes = shiftRes + subG + 2
    1258           0 :                   subG = subG + 1
    1259             :                END DO
    1260             :             END DO grad_do
    1261           0 :             ii0 = ii0 + inSize
    1262           0 :             shiftRes_0 = shiftRes_0 + newSize
    1263           0 :             msize_p = msize_p + inSize
    1264             :          END DO
    1265             :       END IF
    1266           0 :    END SUBROUTINE
    1267             : 
    1268             : ! **************************************************************************************************
    1269             : !> \brief unevaluates a 2d polymial to a 3d polynomial at x
    1270             : !>  p(a,b,c)=p(a,b,c)+sum(pRes(b,c)*(x*a)^i,i), this is *not* the inverse of poly_p_eval3
    1271             : !>  adds to p
    1272             : !> \param p ...
    1273             : !> \param x ...
    1274             : !> \param pRes ...
    1275             : !> \param npoly ...
    1276             : ! **************************************************************************************************
    1277           0 :    SUBROUTINE poly_padd_uneval3(p, x, pRes, npoly)
    1278             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: p
    1279             :       REAL(dp), INTENT(in)                               :: x
    1280             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: pRes
    1281             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1282             : 
    1283             :       INTEGER                                            :: grad, my_npoly, newSize, size_p
    1284           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: xi
    1285             : 
    1286           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1287           0 :       my_npoly = 1
    1288           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1289           0 :       size_p = SIZE(p)/my_npoly
    1290           0 :       newSize = SIZE(pRes)/my_npoly
    1291           0 :       grad = grad_size2(newSize)
    1292           0 :       CPASSERT(size_p >= poly_size3(grad))
    1293           0 :       CPASSERT(newSize == poly_size2(grad))
    1294           0 :       ALLOCATE (xi(grad + 1))
    1295           0 :       CALL poly_padd_uneval3b(p, SIZE(p), x, pRes, SIZE(pRes), my_npoly, grad, xi)
    1296           0 :       DEALLOCATE (xi)
    1297           0 :    END SUBROUTINE
    1298             : 
    1299             : ! **************************************************************************************************
    1300             : !> \brief low level routine of poly_padd_uneval3 without checks
    1301             : !> \param p ...
    1302             : !> \param size_p ...
    1303             : !> \param x ...
    1304             : !> \param pRes ...
    1305             : !> \param size_pRes ...
    1306             : !> \param npoly ...
    1307             : !> \param grad ...
    1308             : !> \param xi ...
    1309             : !> \note loop should be structured differently (more contiguous pRes access)
    1310             : ! **************************************************************************************************
    1311           0 :    SUBROUTINE poly_padd_uneval3b(p, size_p, x, pRes, size_pRes, npoly, grad, xi)
    1312             :       INTEGER, INTENT(in)                                :: size_p
    1313             :       REAL(dp), DIMENSION(IF_CHECK(size_p, *)), &
    1314             :          INTENT(inout)                                   :: p
    1315             :       REAL(dp), INTENT(in)                               :: x
    1316             :       INTEGER, INTENT(in)                                :: size_pRes
    1317             :       REAL(dp), DIMENSION(IF_CHECK(size_pRes, *)), &
    1318             :          INTENT(in)                                      :: pRes
    1319             :       INTEGER, INTENT(in)                                :: npoly, grad
    1320             :       REAL(dp), DIMENSION(IF_CHECK(grad+1, *)), &
    1321             :          INTENT(inout)                                   :: xi
    1322             : 
    1323             :       INTEGER                                            :: i, igrad, ii, ii0, inSize, ipoly, j, &
    1324             :                                                             msize_p, newSize, pShift, shiftRes, &
    1325             :                                                             shiftRes_0, subG, upSize
    1326             : 
    1327           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1328           0 :       inSize = size_p/npoly
    1329           0 :       newSize = size_pRes/npoly
    1330           0 :       upSize = (grad + 1)*(grad + 2)*(grad + 3)/6
    1331           0 :       xi(1) = 1.0
    1332           0 :       DO i = 1, grad
    1333           0 :          xi(i + 1) = xi(i)*x
    1334             :       END DO
    1335             :       shiftRes = 0
    1336             :       pShift = 0
    1337           0 :       DO ipoly = 1, npoly
    1338           0 :          DO ii = 1, MIN(upSize, cached_dim3)
    1339           0 :             p(pShift + ii) = p(pShift + ii) + pRes(shiftRes + a_reduce_idx3(ii))*xi(a_mono_exp3(1, ii) + 1)
    1340             :          END DO
    1341           0 :          shiftRes = shiftRes + newSize
    1342           0 :          pShift = pShift + inSize
    1343             :       END DO
    1344           0 :       IF (grad > max_grad3) THEN
    1345             :          ii0 = (max_grad3 + 1)*(max_grad3 + 2)*(max_grad3 + 3)/6 + 1
    1346             :          shiftRes_0 = 1
    1347             :          msize_p = upSize
    1348           0 :          DO ipoly = 1, npoly
    1349             :             ii = ii0
    1350           0 :             grad_do: DO igrad = max_grad3 + 1, grad
    1351             :                !ii=igrad*(igrad+1)*(igrad+2)/6+1
    1352             :                shiftRes = shiftRes_0
    1353             :                subG = 0
    1354           0 :                DO i = igrad, 0, -1
    1355             :                   !subG=igrad-i
    1356             :                   !shiftRes=subG*(subG+3)/2+1
    1357           0 :                   DO j = subG, 0, -1
    1358           0 :                      IF (msize_p < ii) EXIT grad_do
    1359           0 :                      p(ii) = p(ii) + pRes(shiftRes - j)*xi(i + 1)
    1360           0 :                      ii = ii + 1
    1361             :                   END DO
    1362           0 :                   shiftRes = shiftRes + subG + 2
    1363           0 :                   subG = subG + 1
    1364             :                END DO
    1365             :             END DO grad_do
    1366           0 :             ii0 = ii0 + inSize
    1367           0 :             shiftRes_0 = shiftRes_0 + newSize
    1368           0 :             msize_p = msize_p + inSize
    1369             :          END DO
    1370             :       END IF
    1371           0 :    END SUBROUTINE
    1372             : 
    1373             : ! **************************************************************************************************
    1374             : !> \brief evaluates the 2d polynomial at x (the result is a polynomial in one variable)
    1375             : !> \param p ...
    1376             : !> \param x ...
    1377             : !> \param pRes ...
    1378             : !> \param npoly ...
    1379             : ! **************************************************************************************************
    1380           0 :    SUBROUTINE poly_p_eval2(p, x, pRes, npoly)
    1381             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
    1382             :       REAL(dp), INTENT(in)                               :: x
    1383             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
    1384             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1385             : 
    1386             :       INTEGER                                            :: grad, my_npoly, newSize, size_p
    1387           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: xi
    1388             : 
    1389           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1390           0 :       my_npoly = 1
    1391           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1392           0 :       size_p = SIZE(p)/my_npoly
    1393           0 :       grad = grad_size2(size_p)
    1394           0 :       newSize = SIZE(pRes)/my_npoly
    1395           0 :       pRes = 0.0_dp
    1396           0 :       CPASSERT(newSize >= poly_size1(grad))
    1397           0 :       ALLOCATE (xi(grad + 1))
    1398           0 :       CALL poly_p_eval2b(p, SIZE(p), x, pRes, SIZE(pRes), my_npoly, grad, xi)
    1399           0 :       DEALLOCATE (xi)
    1400           0 :    END SUBROUTINE
    1401             : 
    1402             : ! **************************************************************************************************
    1403             : !> \brief low level routine of poly_p_eval2 without checks
    1404             : !> \param p ...
    1405             : !> \param size_p ...
    1406             : !> \param x ...
    1407             : !> \param pRes ...
    1408             : !> \param size_pRes ...
    1409             : !> \param npoly ...
    1410             : !> \param grad ...
    1411             : !> \param xi ...
    1412             : ! **************************************************************************************************
    1413           0 :    SUBROUTINE poly_p_eval2b(p, size_p, x, pRes, size_pRes, npoly, grad, xi)
    1414             :       INTEGER, INTENT(in)                                :: size_p
    1415             :       REAL(dp), DIMENSION(IF_CHECK(size_p, *)), &
    1416             :          INTENT(in)                                      :: p
    1417             :       REAL(dp), INTENT(in)                               :: x
    1418             :       INTEGER, INTENT(in)                                :: size_pRes
    1419             :       REAL(dp), DIMENSION(IF_CHECK(size_pRes, *)), &
    1420             :          INTENT(inout)                                   :: pRes
    1421             :       INTEGER, INTENT(in)                                :: npoly
    1422             :       INTEGER                                            :: grad
    1423             :       REAL(dp), DIMENSION(IF_CHECK(grad+1, *))           :: xi
    1424             : 
    1425             :       INTEGER                                            :: i, igrad, ii, ii0, ij, inSize, ipoly, &
    1426             :                                                             msize_p, newSize, pShift, shiftRes
    1427             : 
    1428           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1429           0 :       inSize = size_p/npoly
    1430           0 :       newSize = size_pRes/npoly
    1431           0 :       pRes(1:size_pRes) = 0.0_dp
    1432             :       !CPPreconditionNoFail(newSize>grad,cp_failure_level,routineP)
    1433           0 :       xi(1) = 1.0_dp
    1434           0 :       DO i = 1, grad
    1435           0 :          xi(i + 1) = xi(i)*x
    1436             :       END DO
    1437             :       shiftRes = 1
    1438             :       pShift = 0
    1439           0 :       DO ipoly = 1, npoly
    1440           0 :          DO ii = 1, MIN(inSize, cached_dim2)
    1441           0 :             pRes(shiftRes + a_mono_exp2(2, ii)) = pRes(shiftRes + a_mono_exp2(2, ii)) + p(pShift + ii)*xi(a_mono_exp2(1, ii) + 1)
    1442             :          END DO
    1443           0 :          shiftRes = shiftRes + newSize
    1444           0 :          pShift = pShift + inSize
    1445             :       END DO
    1446           0 :       IF (grad > max_grad2) THEN
    1447             :          ii0 = (max_grad2 + 1)*(max_grad2 + 2)/2 + 1
    1448             :          shiftRes = 1
    1449             :          msize_p = inSize
    1450           0 :          DO ipoly = 1, npoly
    1451             :             ii = ii0
    1452           0 :             grad_do2: DO igrad = max_grad2 + 1, grad
    1453             :                !ii=igrad*(igrad+1)/2+1
    1454             :                ij = shiftRes
    1455           0 :                DO i = igrad, 0, -1
    1456           0 :                   IF (msize_p < ii) EXIT grad_do2
    1457             :                   ! ij=igrad-i
    1458           0 :                   pRes(ij) = pRes(ij) + p(ii)*xi(i + 1)
    1459           0 :                   ii = ii + 1
    1460           0 :                   ij = ij + 1
    1461             :                END DO
    1462             :             END DO grad_do2
    1463           0 :             msize_p = msize_p + inSize
    1464           0 :             shiftRes = shiftRes + newSize
    1465           0 :             ii0 = ii0 + inSize
    1466             :          END DO
    1467             :       END IF
    1468           0 :    END SUBROUTINE
    1469             : 
    1470             : ! **************************************************************************************************
    1471             : !> \brief unevaluates a 1d polynomial to 2d at x
    1472             : !>  p(a,b)=sum(pRes(b)*(x*a)^i,i), this is *not* the inverse of poly_p_eval2
    1473             : !>  overwrites p
    1474             : !> \param p ...
    1475             : !> \param x ...
    1476             : !> \param pRes ...
    1477             : !> \param npoly ...
    1478             : ! **************************************************************************************************
    1479           0 :    SUBROUTINE poly_padd_uneval2(p, x, pRes, npoly)
    1480             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: p
    1481             :       REAL(dp), INTENT(in)                               :: x
    1482             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: pRes
    1483             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1484             : 
    1485             :       INTEGER                                            :: grad, my_npoly, newSize, size_p
    1486           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: xi
    1487             : 
    1488           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1489           0 :       my_npoly = 1
    1490           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1491           0 :       size_p = SIZE(p)/my_npoly
    1492           0 :       newSize = SIZE(pRes)/my_npoly
    1493           0 :       grad = grad_size1(newSize)
    1494           0 :       CPASSERT(size_p >= poly_size2(grad))
    1495           0 :       CPASSERT(newSize == poly_size1(grad))
    1496           0 :       ALLOCATE (xi(grad + 1))
    1497           0 :       CALL poly_padd_uneval2b(p, SIZE(p), x, pRes, SIZE(pRes), my_npoly, grad, xi)
    1498           0 :       DEALLOCATE (xi)
    1499           0 :    END SUBROUTINE
    1500             : 
    1501             : ! **************************************************************************************************
    1502             : !> \brief low level routine of poly_p_uneval2 without checks
    1503             : !> \param p ...
    1504             : !> \param size_p ...
    1505             : !> \param x ...
    1506             : !> \param pRes ...
    1507             : !> \param size_pRes ...
    1508             : !> \param npoly ...
    1509             : !> \param grad ...
    1510             : !> \param xi ...
    1511             : ! **************************************************************************************************
    1512           0 :    SUBROUTINE poly_padd_uneval2b(p, size_p, x, pRes, size_pRes, npoly, grad, xi)
    1513             :       INTEGER, INTENT(in)                                :: size_p
    1514             :       REAL(dp), DIMENSION(IF_CHECK(size_p, *)), &
    1515             :          INTENT(inout)                                   :: p
    1516             :       REAL(dp), INTENT(in)                               :: x
    1517             :       INTEGER, INTENT(in)                                :: size_pRes
    1518             :       REAL(dp), DIMENSION(IF_CHECK(size_pRes, *)), &
    1519             :          INTENT(in)                                      :: pRes
    1520             :       INTEGER, INTENT(in)                                :: npoly
    1521             :       INTEGER                                            :: grad
    1522             :       REAL(dp), DIMENSION(IF_CHECK(grad+1, *))           :: xi
    1523             : 
    1524             :       INTEGER                                            :: i, igrad, ii, ii0, ij, inSize, ipoly, &
    1525             :                                                             msize_p, newSize, pShift, shiftRes, &
    1526             :                                                             upSize
    1527             : 
    1528           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1529           0 :       inSize = size_p/npoly
    1530           0 :       upSize = (grad + 1)*(grad + 2)/2
    1531           0 :       newSize = size_pRes/npoly
    1532             :       !CPPreconditionNoFail(newSize>grad,cp_failure_level,routineP)
    1533           0 :       xi(1) = 1.0_dp
    1534           0 :       DO i = 1, grad
    1535           0 :          xi(i + 1) = xi(i)*x
    1536             :       END DO
    1537             :       shiftRes = 1
    1538             :       pShift = 0
    1539           0 :       DO ipoly = 1, npoly
    1540           0 :          DO ii = 1, MIN(upSize, cached_dim2)
    1541           0 :             p(pShift + ii) = p(pShift + ii) + pRes(shiftRes + a_mono_exp2(2, ii))*xi(a_mono_exp2(1, ii) + 1)
    1542             :          END DO
    1543           0 :          shiftRes = shiftRes + newSize
    1544           0 :          pShift = pShift + inSize
    1545             :       END DO
    1546           0 :       IF (grad > max_grad2) THEN
    1547             :          ii0 = (max_grad2 + 1)*(max_grad2 + 2)/2 + 1
    1548             :          shiftRes = 1
    1549             :          msize_p = upSize
    1550           0 :          DO ipoly = 1, npoly
    1551             :             ii = ii0
    1552           0 :             grad_do2: DO igrad = max_grad2 + 1, grad
    1553             :                !ii=igrad*(igrad+1)/2+1
    1554             :                ij = shiftRes
    1555           0 :                DO i = igrad, 0, -1
    1556           0 :                   IF (msize_p < ii) EXIT grad_do2
    1557             :                   ! ij=igrad-i
    1558           0 :                   p(ii) = p(ii) + pRes(ij)*xi(i + 1)
    1559           0 :                   ii = ii + 1
    1560           0 :                   ij = ij + 1
    1561             :                END DO
    1562             :             END DO grad_do2
    1563           0 :             msize_p = msize_p + inSize
    1564           0 :             shiftRes = shiftRes + newSize
    1565           0 :             ii0 = ii0 + inSize
    1566             :          END DO
    1567             :       END IF
    1568           0 :    END SUBROUTINE
    1569             : 
    1570             : ! **************************************************************************************************
    1571             : !> \brief evaluates the 1d polynomial at the given place, results are stored contiguosly
    1572             : !> \param p ...
    1573             : !> \param x ...
    1574             : !> \param pRes ...
    1575             : !> \param npoly ...
    1576             : ! **************************************************************************************************
    1577           0 :    SUBROUTINE poly_eval1(p, x, pRes, npoly)
    1578             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
    1579             :       REAL(dp), INTENT(in)                               :: x
    1580             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
    1581             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1582             : 
    1583             :       INTEGER                                            :: i, ipoly, my_npoly, pShift, size_p
    1584             :       REAL(dp)                                           :: vv, xx
    1585             : 
    1586           0 :       my_npoly = 1
    1587           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1588           0 :       size_p = SIZE(p)/my_npoly
    1589           0 :       CPASSERT(SIZE(pRes) >= my_npoly)
    1590           0 :       pShift = 0
    1591           0 :       DO ipoly = 1, my_npoly
    1592             :          xx = 1.0_dp
    1593             :          vv = 0.0_dp
    1594           0 :          DO i = 1, size_p
    1595           0 :             vv = vv + p(pShift + i)*xx
    1596           0 :             xx = xx*x
    1597             :          END DO
    1598           0 :          pRes(ipoly) = vv
    1599           0 :          pShift = pShift + size_p
    1600             :       END DO
    1601           0 :    END SUBROUTINE
    1602             : 
    1603             : ! **************************************************************************************************
    1604             : !> \brief evaluates the 2d polynomial at the given place, results are stored contiguosly
    1605             : !> \param p ...
    1606             : !> \param x ...
    1607             : !> \param y ...
    1608             : !> \param pRes ...
    1609             : !> \param npoly ...
    1610             : ! **************************************************************************************************
    1611           0 :    SUBROUTINE poly_eval2(p, x, y, pRes, npoly)
    1612             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
    1613             :       REAL(dp), INTENT(in)                               :: x, y
    1614             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
    1615             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1616             : 
    1617             :       INTEGER                                            :: grad, i, igrad, ii, ipoly, j, msize_p, &
    1618             :                                                             my_npoly, pShift, size_p
    1619             :       REAL(dp)                                           :: v
    1620           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: xi, yi
    1621             : 
    1622           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1623           0 :       my_npoly = 1
    1624           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1625           0 :       size_p = SIZE(p)/my_npoly
    1626           0 :       grad = grad_size2(size_p)
    1627           0 :       CPASSERT(SIZE(pRes) >= my_npoly)
    1628           0 :       ALLOCATE (xi(grad + 1), yi(grad + 1))
    1629           0 :       xi(1) = 1.0_dp
    1630           0 :       DO i = 1, grad
    1631           0 :          xi(i + 1) = xi(i)*x
    1632             :       END DO
    1633           0 :       yi(1) = 1.0_dp
    1634           0 :       DO i = 1, grad
    1635           0 :          yi(i + 1) = yi(i)*y
    1636             :       END DO
    1637             :       pShift = 0
    1638           0 :       DO ipoly = 1, my_npoly
    1639           0 :          v = 0.0_dp
    1640           0 :          DO ii = 1, MIN(size_p, cached_dim2)
    1641           0 :             v = v + p(pShift + ii)*xi(a_mono_exp2(1, ii) + 1)*yi(a_mono_exp2(2, ii) + 1)
    1642             :          END DO
    1643           0 :          pRes(ipoly) = v
    1644           0 :          pShift = pShift + size_p
    1645             :       END DO
    1646           0 :       IF (grad > max_grad2) THEN
    1647             :          pShift = (max_grad2 + 1)*(max_grad2 + 2)/2 + 1
    1648             :          msize_p = size_p
    1649           0 :          DO ipoly = 1, my_npoly
    1650             :             ii = pShift
    1651             :             v = 0.0_dp
    1652           0 :             grad_do4: DO igrad = max_grad2 + 1, grad
    1653             :                ! ii=igrad*(igrad+1)*(igrad+2)/6+1
    1654             :                j = 1
    1655           0 :                DO i = igrad, 0, -1
    1656           0 :                   IF (msize_p < ii) EXIT grad_do4
    1657           0 :                   v = v + p(ii)*xi(i + 1)*yi(j)
    1658           0 :                   j = j + 1
    1659           0 :                   ii = ii + 1
    1660             :                END DO
    1661             :             END DO grad_do4
    1662           0 :             pRes(ipoly) = pRes(ipoly) + v
    1663           0 :             pShift = pShift + size_p
    1664           0 :             msize_p = msize_p + size_p
    1665             :          END DO
    1666             :       END IF
    1667           0 :    END SUBROUTINE
    1668             : 
    1669             : ! **************************************************************************************************
    1670             : !> \brief evaluates the 3d polynomial at the given place, results are stored contiguosly
    1671             : !> \param p ...
    1672             : !> \param x ...
    1673             : !> \param y ...
    1674             : !> \param z ...
    1675             : !> \param pRes ...
    1676             : !> \param npoly ...
    1677             : ! **************************************************************************************************
    1678           0 :    SUBROUTINE poly_eval3(p, x, y, z, pRes, npoly)
    1679             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
    1680             :       REAL(dp), INTENT(in)                               :: x, y, z
    1681             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
    1682             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1683             : 
    1684             :       INTEGER                                            :: grad, i, igrad, ii, ipoly, j, k, &
    1685             :                                                             msize_p, my_npoly, pShift, size_p
    1686             :       REAL(dp)                                           :: v
    1687           0 :       REAL(dp), ALLOCATABLE, DIMENSION(:)                :: xi, yi, zi
    1688             : 
    1689           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1690           0 :       my_npoly = 1
    1691           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1692           0 :       size_p = SIZE(p)/my_npoly
    1693           0 :       grad = grad_size3(size_p)
    1694           0 :       CPASSERT(SIZE(pRes) >= my_npoly)
    1695           0 :       ALLOCATE (xi(grad + 1), yi(grad + 1), zi(grad + 1))
    1696           0 :       xi(1) = 1.0_dp
    1697           0 :       DO i = 1, grad
    1698           0 :          xi(i + 1) = xi(i)*x
    1699             :       END DO
    1700           0 :       yi(1) = 1.0_dp
    1701           0 :       DO i = 1, grad
    1702           0 :          yi(i + 1) = yi(i)*y
    1703             :       END DO
    1704           0 :       zi(1) = 1.0_dp
    1705           0 :       DO i = 1, grad
    1706           0 :          zi(i + 1) = zi(i)*z
    1707             :       END DO
    1708             :       pShift = 0
    1709           0 :       DO ipoly = 1, my_npoly
    1710           0 :          v = 0.0_dp
    1711           0 :          DO ii = 1, MIN(size_p, cached_dim3)
    1712             :             v = v + p(pShift + ii)*xi(a_mono_exp3(1, ii) + 1)*yi(a_mono_exp3(2, ii) + 1) &
    1713           0 :                 *zi(a_mono_exp3(3, ii) + 1)
    1714             :          END DO
    1715           0 :          pRes(ipoly) = v
    1716           0 :          pShift = pShift + size_p
    1717             :       END DO
    1718           0 :       IF (grad > max_grad3) THEN
    1719           0 :          pShift = (max_grad3 + 1)*(max_grad3 + 2)*(max_grad3 + 3)/6 + 1
    1720           0 :          msize_p = size_p
    1721           0 :          DO ipoly = 1, my_npoly
    1722           0 :             ii = pShift
    1723             :             v = 0.0_dp
    1724           0 :             grad_do3: DO igrad = max_grad3 + 1, grad
    1725             :                ! ii=igrad*(igrad+1)*(igrad+2)/6+1
    1726           0 :                DO i = igrad, 0, -1
    1727           0 :                   k = 1
    1728           0 :                   DO j = igrad - i, 0, -1
    1729           0 :                      ii = (ipoly - 1)*size_p + mono_index3(i, j, igrad - i - j) + 1
    1730           0 :                      IF (msize_p < ii) EXIT grad_do3
    1731           0 :                      v = v + p(ii)*xi(i + 1)*yi(j + 1)*zi(k)
    1732           0 :                      k = k + 1
    1733           0 :                      ii = ii + 1
    1734             :                   END DO
    1735             :                END DO
    1736             :             END DO grad_do3
    1737           0 :             pRes(ipoly) = pRes(ipoly) + v
    1738           0 :             pShift = pShift + size_p
    1739           0 :             msize_p = msize_p + size_p
    1740             :          END DO
    1741             :       END IF
    1742           0 :    END SUBROUTINE
    1743             : 
    1744             : ! **************************************************************************************************
    1745             : !> \brief returns an array with all dp/dx, the all dp/dy, and finally all dp/dz
    1746             : !> \param p ...
    1747             : !> \param pRes ...
    1748             : !> \param npoly ...
    1749             : !> \param sumUp ...
    1750             : ! **************************************************************************************************
    1751           0 :    SUBROUTINE poly_derive3(p, pRes, npoly, sumUp)
    1752             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: p
    1753             :       REAL(dp), DIMENSION(:), INTENT(inout)              :: pRes
    1754             :       INTEGER, INTENT(in), OPTIONAL                      :: npoly
    1755             :       LOGICAL, INTENT(in), OPTIONAL                      :: sumUp
    1756             : 
    1757             :       INTEGER :: grad, i, igrad, ii, ii2, ipoly, j, k, msize_p, my_npoly, newSize, pShift, size_p, &
    1758             :          xDerivShift, yDerivShift, yShift, zDerivShift, zShift
    1759             :       LOGICAL                                            :: my_sumUp
    1760             : 
    1761           0 :       IF (.NOT. module_initialized) CPABORT("module d3_poly not initialized")
    1762           0 :       my_npoly = 1
    1763           0 :       IF (PRESENT(npoly)) my_npoly = npoly
    1764           0 :       my_sumUp = .FALSE.
    1765           0 :       IF (PRESENT(sumUp)) my_sumUp = sumUp
    1766           0 :       size_p = SIZE(p)/my_npoly
    1767           0 :       newSize = SIZE(pRes)/(3*my_npoly)
    1768           0 :       grad = grad_size3(size_p)
    1769           0 :       CPASSERT(newSize >= poly_size3(grad))
    1770           0 :       IF (.NOT. my_sumUp) pRes = 0
    1771           0 :       xDerivShift = 1
    1772           0 :       yDerivShift = my_npoly*newSize + 1
    1773           0 :       zDerivShift = 2*yDerivShift - 1
    1774           0 :       pShift = 0
    1775           0 :       DO ipoly = 1, my_npoly
    1776             :          ! split derivs to have less streams to follow (3 vs 5)?
    1777           0 :          DO ii = 1, MIN(cached_dim3, size_p)
    1778             :             pRes(xDerivShift + a_deriv_idx3(1, ii)) = pRes(xDerivShift + a_deriv_idx3(1, ii)) &
    1779           0 :                                                       + p(pShift + ii)*a_mono_exp3(1, ii)
    1780             :             pRes(yDerivShift + a_deriv_idx3(2, ii)) = pRes(yDerivShift + a_deriv_idx3(2, ii)) &
    1781           0 :                                                       + p(pShift + ii)*a_mono_exp3(2, ii)
    1782             :             pRes(zDerivShift + a_deriv_idx3(3, ii)) = pRes(zDerivShift + a_deriv_idx3(3, ii)) &
    1783           0 :                                                       + p(pShift + ii)*a_mono_exp3(3, ii)
    1784             :          END DO
    1785           0 :          xDerivShift = xDerivShift + newSize
    1786           0 :          yDerivShift = yDerivShift + newSize
    1787           0 :          zDerivShift = zDerivShift + newSize
    1788           0 :          pShift = pShift + size_p
    1789             :       END DO
    1790           0 :       IF (grad > max_grad3) THEN
    1791           0 :          xDerivShift = 0
    1792           0 :          yDerivShift = my_npoly*newSize
    1793           0 :          zDerivShift = 2*yDerivShift - 1
    1794           0 :          msize_p = size_p
    1795           0 :          xDerivShift = max_grad3*(max_grad3 + 1)*(max_grad3 + 2)/6 + 1
    1796           0 :          pShift = xDerivShift + (max_grad3 + 1)*(max_grad3 + 2)/2
    1797           0 :          DO ipoly = 1, my_npoly
    1798             :             ii = pShift
    1799             :             ii2 = xDerivShift
    1800           0 :             grad_do5: DO igrad = max_grad3 + 1, grad
    1801             :                yShift = yDerivShift
    1802             :                zShift = zDerivShift
    1803           0 :                DO i = igrad, 0, -1
    1804           0 :                   k = 0
    1805           0 :                   DO j = igrad - i, 0, -1
    1806           0 :                      IF (ii > msize_p) EXIT grad_do5
    1807             :                      ! remove ifs?
    1808           0 :                      IF (i > 0) pRes(ii2) = pRes(ii2) + p(ii)*i
    1809           0 :                      IF (j > 0) pRes(yShift + ii2) = pRes(yShift + ii2) + p(ii)*j
    1810           0 :                      IF (k > 0) pRes(zShift + ii2) = pRes(zShift + ii2) + k*p(ii)
    1811           0 :                      ii = ii + 1
    1812           0 :                      ii2 = ii2 + 1
    1813           0 :                      k = k + 1
    1814             :                   END DO
    1815           0 :                   yShift = yShift - 1
    1816           0 :                   zShift = zShift - 1
    1817             :                END DO
    1818           0 :                ii2 = ii2 - igrad - 1
    1819             :             END DO grad_do5
    1820           0 :             pShift = pShift + size_p
    1821           0 :             xDerivShift = xDerivShift + newSize
    1822           0 :             msize_p = msize_p + size_p
    1823             :          END DO
    1824             :       END IF
    1825           0 :    END SUBROUTINE
    1826             : 
    1827             : ! **************************************************************************************************
    1828             : !> \brief subroutine that converts from the cp2k poly format to the d3 poly format
    1829             : !> \param poly_cp2k ...
    1830             : !> \param grad ...
    1831             : !> \param poly_d3 ...
    1832             : ! **************************************************************************************************
    1833           0 :    SUBROUTINE poly_cp2k2d3(poly_cp2k, grad, poly_d3)
    1834             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: poly_cp2k
    1835             :       INTEGER, INTENT(in)                                :: grad
    1836             :       REAL(dp), DIMENSION(:), INTENT(out)                :: poly_d3
    1837             : 
    1838             :       INTEGER                                            :: cp_ii, i, j, k, mgrad, mgrad2, sgrad, &
    1839             :                                                             sgrad2, sgrad2k, sgrad3, sgrad3k, &
    1840             :                                                             shifti, shiftj, shiftk, size_p
    1841             : 
    1842           0 :       size_p = (grad + 1)*(grad + 2)*(grad + 3)/6
    1843           0 :       CPASSERT(SIZE(poly_cp2k) >= size_p)
    1844           0 :       CPASSERT(SIZE(poly_d3) >= size_p)
    1845           0 :       cp_ii = 0
    1846           0 :       sgrad2k = 0
    1847           0 :       sgrad3k = 0
    1848           0 :       DO k = 0, grad
    1849           0 :          shiftk = k + 1
    1850           0 :          sgrad2k = sgrad2k + k
    1851           0 :          sgrad3k = sgrad3k + sgrad2k
    1852           0 :          sgrad2 = sgrad2k
    1853           0 :          sgrad3 = sgrad3k
    1854           0 :          DO j = 0, grad - k
    1855           0 :             sgrad = j + k
    1856           0 :             mgrad2 = sgrad2
    1857           0 :             shiftj = mgrad2 + shiftk
    1858           0 :             mgrad = sgrad
    1859           0 :             shifti = shiftj + sgrad3
    1860           0 :             DO i = 0, grad - j - k
    1861           0 :                cp_ii = cp_ii + 1
    1862           0 :                poly_d3(shifti) = poly_cp2k(cp_ii)
    1863           0 :                mgrad = mgrad + 1
    1864           0 :                mgrad2 = mgrad2 + mgrad
    1865           0 :                shifti = shifti + mgrad2
    1866             :             END DO
    1867           0 :             sgrad2 = sgrad2 + sgrad + 1
    1868           0 :             sgrad3 = sgrad3 + sgrad2
    1869             :          END DO
    1870             :       END DO
    1871           0 :       IF (SIZE(poly_d3) >= size_p) THEN
    1872           0 :          poly_d3(size_p + 1:) = 0.0_dp
    1873             :       END IF
    1874           0 :    END SUBROUTINE
    1875             : 
    1876             : ! **************************************************************************************************
    1877             : !> \brief subroutine that converts from the d3 poly format to the cp2k poly format
    1878             : !> \param poly_cp2k ...
    1879             : !> \param grad ...
    1880             : !> \param poly_d3 ...
    1881             : ! **************************************************************************************************
    1882           0 :    SUBROUTINE poly_d32cp2k(poly_cp2k, grad, poly_d3)
    1883             :       REAL(dp), DIMENSION(:), INTENT(out)                :: poly_cp2k
    1884             :       INTEGER, INTENT(in)                                :: grad
    1885             :       REAL(dp), DIMENSION(:), INTENT(in)                 :: poly_d3
    1886             : 
    1887             :       INTEGER                                            :: cp_ii, i, j, k, mgrad, mgrad2, sgrad, &
    1888             :                                                             sgrad2, sgrad2k, sgrad3, sgrad3k, &
    1889             :                                                             shifti, shiftj, shiftk, size_p
    1890             : 
    1891           0 :       size_p = (grad + 1)*(grad + 2)*(grad + 3)/6
    1892           0 :       CPASSERT(SIZE(poly_cp2k) >= size_p)
    1893           0 :       CPASSERT(SIZE(poly_d3) >= size_p)
    1894           0 :       cp_ii = 0
    1895           0 :       sgrad2k = 0
    1896           0 :       sgrad3k = 0
    1897           0 :       DO k = 0, grad
    1898           0 :          shiftk = k + 1
    1899           0 :          sgrad2k = sgrad2k + k
    1900           0 :          sgrad3k = sgrad3k + sgrad2k
    1901           0 :          sgrad2 = sgrad2k
    1902           0 :          sgrad3 = sgrad3k
    1903           0 :          DO j = 0, grad - k
    1904           0 :             sgrad = j + k
    1905           0 :             mgrad2 = sgrad2
    1906           0 :             shiftj = mgrad2 + shiftk
    1907           0 :             mgrad = sgrad
    1908           0 :             shifti = shiftj + sgrad3
    1909           0 :             DO i = 0, grad - j - k
    1910           0 :                cp_ii = cp_ii + 1
    1911           0 :                poly_cp2k(cp_ii) = poly_d3(shifti)
    1912           0 :                mgrad = mgrad + 1
    1913           0 :                mgrad2 = mgrad2 + mgrad
    1914           0 :                shifti = shifti + mgrad2
    1915             :             END DO
    1916           0 :             sgrad2 = sgrad2 + sgrad + 1
    1917           0 :             sgrad3 = sgrad3 + sgrad2
    1918             :          END DO
    1919             :       END DO
    1920           0 :       IF (SIZE(poly_d3) >= size_p) THEN
    1921           0 :          poly_cp2k(size_p + 1:) = 0.0_dp
    1922             :       END IF
    1923           0 :    END SUBROUTINE
    1924             : 
    1925             : END MODULE d3_poly

Generated by: LCOV version 1.15