The problem is, that if you make multiply with [300], to a numpy
array, it will expand the last axis.

Reshaping that into a usable form is the problem.

I spent many many many hours, to get to this:
# Reshape dw to per experiment and nr spins. Or for R20A per
experiment, spin and frequency.
[300] -> [1, 300]    :     [300] -> [1, 100, 3]

# Expand axis
[1, 300] -> [1, 300, 1, 1, 1] : [1, 100, 3]-> [1, 100, 3, 1, 1]

# Then tile to dimensions
[1, 300, 1, 1, 1] -> [1, 300, 3, 1, 22]      :     [1, 100, 3, 1, 22]

This is a very logic build up of the shapes.
The add or multiply would multiply to the last axis.

The only thing I could do, was to create newaxis.
And then tile up!

--------- Example code to play with.
import numpy as np
s = [1, 100, 3, 1, 22]
print "dw"
dw = np.asarray(range(100))
print dw.shape
dw1 = dw.reshape( (s[0], s[1]) )
print dw1.shape
dw2 = dw1[:,:,None,None,None]
print dw2.shape
dw3 = np.tile(dw2, (1, 1, s[2], s[3], s[4]))
print dw3.shape

print "r20"
r = np.asarray(range(300))
print r.shape
r1 = r.reshape( (s[0], s[1], s[2]) )
print r1.shape
r2 = r1[:,:,:,None,None]
print r2.shape
r3 = np.tile(r2, (1, 1, 1, s[3], s[4]))
print r3.shape
-------------------


With this, I think I am done!

I really would like to wrap this up and continue with my own stuff.
So, what needs to be done, before you can accept this?

I will:
Expand to other CPMG models, which are analytical
Include R1rho.
I cannot do for numerical, do to the looping.

Should I add unit tests for each?


------------ No time saved on one spin, but 21X speed up on clustering !
3 frq,
1000 iterations


   ncalls  tottime  percall  cumtime  percall filename:lineno(function)

1 spin
        1    0.000    0.000    0.351    0.351 <string>:1(<module>)
        1    0.001    0.001    0.351    0.351 profiling_cr72.py:427(single)
     1000    0.001    0.000    0.341    0.000 profiling_cr72.py:413(calc)
     1000    0.009    0.000    0.340    0.000 relax_disp.py:989(func_CR72_full)
     1000    0.024    0.000    0.327    0.000 relax_disp.py:523(calc_CR72_chi2)
     1003    0.088    0.000    0.237    0.000 cr72.py:101(r2eff_CR72)
     2003    0.035    0.000    0.122    0.000 numeric.py:2056(allclose)
    10046    0.051    0.000    0.051    0.000 {method 'reduce' of
'numpy.ufunc' objects}
     3000    0.029    0.000    0.047    0.000 shape_base.py:761(tile)
     4015    0.005    0.000    0.035    0.000 fromnumeric.py:1762(any)

100 spin
        1    0.000    0.000    1.507    1.507 <string>:1(<module>)
        1    0.001    0.001    1.507    1.507 profiling_cr72.py:449(cluster)
     1000    0.001    0.000    1.433    0.001 profiling_cr72.py:413(calc)
     1000    0.010    0.000    1.432    0.001 relax_disp.py:989(func_CR72_full)
     1000    0.052    0.000    1.413    0.001 relax_disp.py:523(calc_CR72_chi2)
     1300    0.917    0.001    1.193    0.001 cr72.py:101(r2eff_CR72)
     2300    0.101    0.000    0.224    0.000 numeric.py:2056(allclose)
     3000    0.034    0.000    0.157    0.000 shape_base.py:761(tile)
     4000    0.108    0.000    0.108    0.000 {method 'repeat' of
'numpy.ndarray' objects}
    11828    0.085    0.000    0.085    0.000 {method 'reduce' of
'numpy.ufunc' objects}
        1    0.000    0.000    0.073    0.073 profiling_cr72.py:106(__init__)
        1    0.013    0.013    0.058    0.058
profiling_cr72.py:173(return_r2eff_arrays)
     1000    0.030    0.000    0.046    0.000 chi2.py:72(chi2_rankN)
     4609    0.006    0.000    0.045    0.000 fromnumeric.py:1762(any)
     2300    0.004    0.000    0.035    0.000 fromnumeric.py:1621(sum)


------------------TRUNK
1 spin
        1    0.000    0.000    0.351    0.351 <string>:1(<module>)
        1    0.001    0.001    0.351    0.351 profiling_cr72.py:427(single)
     1000    0.001    0.000    0.343    0.000 profiling_cr72.py:413(calc)
     1000    0.008    0.000    0.342    0.000 relax_disp.py:911(func_CR72_full)
     1000    0.032    0.000    0.330    0.000 relax_disp.py:456(calc_CR72_chi2)
     3003    0.177    0.000    0.246    0.000 cr72.py:100(r2eff_CR72)
    12036    0.061    0.000    0.061    0.000 {method 'reduce' of
'numpy.ufunc' objects}
     3000    0.025    0.000    0.049    0.000 chi2.py:32(chi2)
     6003    0.008    0.000    0.049    0.000 fromnumeric.py:1621(sum)


        1    0.000    0.000   32.180   32.180 <string>:1(<module>)
        1    0.001    0.001   32.180   32.180 profiling_cr72.py:449(cluster)
     1000    0.001    0.000   32.132    0.032 profiling_cr72.py:413(calc)
     1000    0.009    0.000   32.131    0.032 relax_disp.py:911(func_CR72_full)
     1000    3.121    0.003   32.112    0.032 relax_disp.py:456(calc_CR72_chi2)
   300300   17.356    0.000   23.903    0.000 cr72.py:100(r2eff_CR72)
  1200927    5.845    0.000    5.845    0.000 {method 'reduce' of
'numpy.ufunc' objects}
   300000    2.503    0.000    4.842    0.000 chi2.py:32(chi2)
   600300    0.762    0.000    4.705    0.000 fromnumeric.py:1621(sum)
   600300    0.608    0.000    3.460    0.000 _methods.py:23(_sum)
   300300    0.287    0.000    2.191    0.000 fromnumeric.py:2048(amax)
   300300    0.281    0.000    1.990    0.000 fromnumeric.py:2132(amin)
   300300    0.325    0.000    1.904    0.000 _methods.py:15(_amax)
   300300    0.296    0.000    1.709    0.000 _methods.py:19(_amin)




2014-06-10 20:57 GMT+02:00 Edward d'Auvergne <[email protected]>:
> Hi,
>
> I'll have a look tomorrow but, as you've probably seen, some of the
> fine details such as indices to be used need to be sorted out when
> implementing this.
>
> Regards,
>
> Edward
>
>
> On 10 June 2014 20:49, Troels Emtekær Linnet <[email protected]> wrote:
>> What ever I do, I cannot get this to work?
>>
>> Can you show an example ?
>>
>> 2014-06-10 16:29 GMT+02:00 Edward d'Auvergne <[email protected]>:
>>> Here is an example of avoiding automatic numpy data structure creation
>>> and then garbage collection:
>>>
>>> """
>>> from numpy import add, ones, zeros
>>>
>>> a = zeros((5, 4))
>>> a[1] = 1
>>> a[:,1] = 2
>>>
>>> b = ones((5, 4))
>>>
>>> add(a, b, a)
>>> print(a)
>>> """
>>>
>>> The result is:
>>>
>>> [[ 1.  3.  1.  1.]
>>>  [ 2.  3.  2.  2.]
>>>  [ 1.  3.  1.  1.]
>>>  [ 1.  3.  1.  1.]
>>>  [ 1.  3.  1.  1.]]
>>>
>>> The out argument for numpy.add() is used here to operate in a similar
>>> way to the Python "+=" operation.  But it avoids the temporary numpy
>>> data structures that the Python "+=" operation will create.  This will
>>> save a lot of time in the dispersion code.
>>>
>>> Regards,
>>>
>>> Edward
>>>
>>>
>>> On 10 June 2014 15:56, Edward d'Auvergne <[email protected]> wrote:
>>>> Hi Troels,
>>>>
>>>> Here is one suggestion, of many that I have, for significantly
>>>> improving the speed of the analytic dispersion models in your
>>>> 'disp_spin_speed' branch.  The speed ups you have currently achieved
>>>> for spin clusters are huge and very impressive.  But now that you have
>>>> the infrastructure in place, you can advance this much more!
>>>>
>>>> The suggestion has to do with the R20, R20A, and R20B numpy data
>>>> structures.  They way they are currently handled is relatively
>>>> inefficient, in that they are created de novo for each function call.
>>>> This means that memory allocation and Python garbage collection
>>>> happens for every single function call - something which should be
>>>> avoided at almost all costs.
>>>>
>>>> A better way to do this would be to have a self.R20_struct,
>>>> self.R20A_struct, and self.R20B_struct created in __init__(), and then
>>>> to pack in the values from the parameter vector into these structures.
>>>> You could create a special structure in __init__() for this.  It would
>>>> have the dimensions [r20_index][ei][si][mi][oi], where the first
>>>> dimension corresponds to the different R20 parameters.  And for each
>>>> r20_index element, you would have ones at the [ei][si][mi][oi]
>>>> positions where you would like R20 to be, and zeros elsewhere.  The
>>>> key is that this is created at the target function start up, and not
>>>> for each function call.
>>>>
>>>> This would be combined with the very powerful 'out' argument set to
>>>> self.R20_struct with the numpy.add() and numpy.multiply() functions to
>>>> prevent all memory allocations and garbage collection.  Masks could be
>>>> used, but I think that that would be much slower than having special
>>>> numpy structures with ones where R20 should be and zeros elsewhere.
>>>> For just creating these structures, looping over a single r20_index
>>>> loop and multiplying by the special [r20_index][ei][si][mi][oi]
>>>> one/zero structure and using numpy.add() and numpy.multiply() with out
>>>> arguments would be much, much faster than masks or the current
>>>> R20_axis logic.  It will also simplify the code.
>>>>
>>>> Regards,
>>>>
>>>> Edward
>>>
>>> _______________________________________________
>>> relax (http://www.nmr-relax.com)
>>>
>>> This is the relax-devel mailing list
>>> [email protected]
>>>
>>> To unsubscribe from this list, get a password
>>> reminder, or change your subscription options,
>>> visit the list information page at
>>> https://mail.gna.org/listinfo/relax-devel

_______________________________________________
relax (http://www.nmr-relax.com)

This is the relax-devel mailing list
[email protected]

To unsubscribe from this list, get a password
reminder, or change your subscription options,
visit the list information page at
https://mail.gna.org/listinfo/relax-devel

Reply via email to