Dear all,

I am trying to implement various schemes for storing Gaunt
coefficients (integrals of 3 spherical harmonics) calculated
symbolically. Ondrej, I remember you offered me help for this, now I
have to ask for it.

It appears that at moderately big indices, already at l_max~30, the
memory is all eaten up. I tried to force garbage collection, without
success. Interestingly, if I repeatedly calculate just one Gaunt
coefficient for a fixed set of indices, there is no memory problem
(commented out in the script below)…

There is no memory leak per se. When I exit from Python, the memory is
fully recovered. It seems that the garbage is not collected during the
calculations, even when asked, untill it occupies the whole memory.

Below I attach a test module. Sorry for the long post: I don’t see a
way how I could attach it as a file (I am using a web form).

Can you recommend me a memory saving approach?

Best regards,
Konstantin

****************************************
import numpy as np
import sympy
import tables
#import gc
import time

factorials=[sympy.Integer(1)]

def get_factorials(nn):
    """ Precalculated factorials """
    if nn >= len(factorials):
        for ii in range(len(factorials), nn + 1):
            factorials.append(factorials[ii - 1] * ii)
    return factorials[:(nn + 1)]

def zero_gaunt_l(l_1, l_2, l_3):
    """
    Checks l indices for giving an even sum and fulfilling the
triangle realtion.
    """
    if np.mod(l_1 + l_2 + l_3, 2) != 0: return True
    if  l_1 + l_2 - l_3 < 0: return True
    if  l_1 - l_2 + l_3 < 0: return True
    if -l_1 + l_2 + l_3 < 0: return True
    return False

def zero_gaunt_m(l_1, l_2, l_3, m_1, m_2, m_3):
    """
    Checks m indices for giving 0 sum and being limited by l's
    """
    if (m_1 + m_2 + m_3) != 0: return True
    if (abs(m_1) > l_1) or (abs(m_2) > l_2) or (abs(m_3) > l_3):
return True
    return False

def gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec=None, include4Pi=True):
    """
    Check validity of the indices and calculate the Gaunt coefficient.
    """
    if type(l_1) != type(l_2) != type(l_3) != type(1):
        raise ValueError("l values must be integer")
    if type(m_1) != type(m_2) != type(m_3) != type(1):
        raise ValueError("m values must be integer")

    if zero_gaunt_l(l_1, l_2, l_3): return 0
    if zero_gaunt_m(l_1, l_2, l_3, m_1, m_2, m_3): return 0

    return calc_gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec, include4Pi)

def calc_gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec=None,
include4Pi=True):
    """
    Calculate the Gaunt coefficient.
    """
    a1 =  l_1 + l_2 - l_3
    a2 =  l_1 - l_2 + l_3
    a3 = -l_1 + l_2 + l_3

    bigL = (l_1 + l_2 + l_3) / 2
    a4 = -l_3 + l_1 + m_2
    a5 = -l_3 + l_2 - m_1
    imin = max(a4, a5, 0)
    a6 = l_2 + m_2
    a7 = l_1 - m_1
    imax = min(a6, a7, a1)

    maxFactorial = max(l_1 + l_2 + l_3, imax) + 1
    get_factorials(maxFactorial)

    trySeparate = True # test whether the factors under sqrt must be
kept
    if trySeparate:
        prefac1 = sympy.sqrt(2 * l_1 + 1) *\
          sympy.sqrt(2 * l_2 + 1) *\
          sympy.sqrt(2 * l_3 + 1) *\
          sympy.sqrt(factorials[a7]) *\
          sympy.sqrt(factorials[l_1 + m_1]) *\
          sympy.sqrt(factorials[l_2 - m_2]) *\
          sympy.sqrt(factorials[a6]) *\
          sympy.sqrt(factorials[l_3 - m_3]) *\
          sympy.sqrt(factorials[l_3 + m_3])
    else:
        prefac1 = sympy.sqrt((2 * l_1 + 1) * (2 * l_2 + 1) * (2 * l_3
+ 1) *\
          factorials[a7] *\
          factorials[l_1 + m_1] *\
          factorials[l_2 - m_2] *\
          factorials[a6] *\
          factorials[l_3 - m_3] *\
          factorials[l_3 + m_3])
    if include4Pi:
        prefac1 /= (sympy.sqrt(sympy.pi) * sympy.Integer(2))

    prefac2 = factorials[bigL] * factorials[a1] * factorials[a2] *
factorials[a3] /\
      (factorials[2 * bigL + 1] *\
      factorials[bigL - l_1] * factorials[bigL - l_2] *
factorials[bigL - l_3])

    sumres = 0
    for ii in range(imin, imax + 1):
        den = factorials[ii] * factorials[a1 - ii] *\
          factorials[ii - a4] * factorials[ii - a5] *\
          factorials[a6 - ii] * factorials[a7 - ii]
        if np.mod(ii, 2) == 0:
            sumres += sympy.Integer(1) / den
        else:
            sumres -= sympy.Integer(1) / den
    res = prefac1 * prefac2 * sumres
    if np.mod((bigL + l_3 + m_1 - m_2), 2) != 0:
        res = -res

    if prec is not None:
        res = res.evalf(prec)
    return res

def store_Rasch_Yu(fileName, l_max):
    filters = tables.Filters(complevel=1, complib='zlib')
#complib='zlib'|'blosc'
    with tables.openFile(fileName, mode = "w") as fileh:
        vlarray0 = fileh.createVLArray(fileh.root, 'vlarray',
tables.ObjectAtom(),
          "pickled Gaunt coeffs", filters=filters,
          expectedsizeinMB=(l_max*0.1)**4)

        zeroList = []
        indices = 0
        for l_1 in xrange(l_max + 1):
            for l_2 in xrange(l_1 + 1):
                for l_3 in xrange(l_2 + 1):
                    if zero_gaunt_l(l_1, l_2, l_3):
                        for m_3 in xrange(l_3 + 1):
#                            vlarray0.append(zeroList)
                            indices += 1
                        continue
                    print l_1, l_2, l_3
                    for m_3 in xrange(l_3 + 1):
                        m3list = []
                        for m_2 in xrange(-l_2, min(l_1 - m_3, l_2) +
1):
                            m_1 = -m_2 - m_3
                            if zero_gaunt_m(l_1, l_2, l_3, m_1, m_2,
m_3):
                                curGaunt = sympy.Integer(0)
                            else:
                                curGaunt = calc_gaunt(l_1, l_2, l_3,
m_1, m_2, m_3,
                                  include4Pi=False)
# if I comment calc_gaunt above and uncomment the one below with a
dummi
# set of indices, there is no memory problem
#                                curGaunt =
calc_gaunt(29,29,34,10,-5,-5,
#                                  include4Pi=False)
                            if type(curGaunt) in \
                              [sympy.core.numbers.Integer,
sympy.core.numbers.Zero,
                              sympy.core.numbers.One,
sympy.core.numbers.NegativeOne]:
                                m2list = curGaunt
                            elif type(curGaunt) ==
sympy.core.numbers.Rational:
                                m2list = [curGaunt.p, curGaunt.q]
                            elif type(curGaunt) == sympy.core.mul.Mul:
                                m2list = [0, 1, 0]
                                for bas_arg in
curGaunt.iter_basic_args():
                                    if type(bas_arg) ==
sympy.core.numbers.Rational:
                                        m2list[0] = bas_arg.p
                                        m2list[1] = bas_arg.q
                                    elif type(bas_arg) ==
sympy.core.power.Pow:
                                        if bas_arg.exp ==
sympy.Integer(1)/2:
                                            m2list[2] = bas_arg.base
                                    else:
                                        raise ValueError('wrong type
of Gaunt atoms')
                                if (m2list[0] == 0) or (m2list[2] ==
0):
                                    raise ValueError('wrong value of
Gaunt')
                            else:
                                print l_1, l_2, l_3, m_1, m_2, m_3
                                print curGaunt, type(curGaunt)
                                raise ValueError('wrong type of Gaunt
result')
                            m3list.append(m2list)
#                        vlarray0.append(m3list)
                        indices += 1
#                        vlarray0.flush()
#            print 'collecting garbage...',
#            gc.collect()
#            print ' done'

    max_index_expected = (l_max + 1) * (l_max + 2) * (l_max + 3) *
(l_max + 4) / 24
    print indices, max_index_expected

if __name__ == '__main__':
#!!!!!!!!!!!!!!!! VERY important !!!!!!!!!!!!!!!!
#in sympy/core/numbers.py, line 1013:
## The following is an algorithm where we collect perfect roots
## from the factors of base
#if b > 4294967296:
#    # Prevent from factorizing too big integers
#    return None
#  <------------------- comment it out!!!
#end of !!!!!!!!!!!!!!!! VERY important !!!!!!!!!!!!!!!!

    tstart = time.time()
    store_Rasch_Yu('test_Rasch_Yu.h5', 30)
    tstop = time.time()
    print 'The calculation took {0:.1f} s'.format(tstop - tstart)

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sympy?hl=en.

Reply via email to