Skip to content

Commit

Permalink
DOC: Updated docstrings in new Analysis class and in IO module
Browse files Browse the repository at this point in the history
Added docstring to Analysis class, and cleaned up docstrings in IO module
  • Loading branch information
pseudocubic committed Mar 22, 2016
1 parent 4c44297 commit 20e2530
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 111 deletions.
240 changes: 134 additions & 106 deletions neutronpy/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,40 @@ def _call_bin_parallel(arg, **kwarg):


class Analysis(object):
r'''Analysis subroutines for the Data class
Attributes
----------
detailed_balance_factor
Methods
-------
integrate
position
width
scattering_function
dynamic_susceptibility
estimate_background
'''
@property
def detailed_balance_factor(self):
r'''Returns the detailed balance factor (sometimes called the Bose
factor)
Parameters
----------
None
Returns
-------
dbf : ndarray
The detailed balance factor (temperature correction)
'''

return 1. - np.exp(-self.Q[:, 3] / BOLTZMANN_IN_MEV_K / self.temp)

def integrate(self, background=None, **kwargs):
r'''Returns the integrated intensity within given bounds
Expand All @@ -42,10 +76,12 @@ def integrate(self, background=None, **kwargs):
if 'bounds' in kwargs:
to_fit = np.where(kwargs['bounds'])
for i in range(4):
result += np.trapz(self.intensity[to_fit] - background, x=self.Q[to_fit, i])
result += np.trapz(self.intensity[to_fit] - background,
x=self.Q[to_fit, i])
else:
for i in range(4):
result += np.trapz(self.intensity - background, x=self.Q[:, i])
result += np.trapz(self.intensity - background,
x=self.Q[:, i])

return result

Expand Down Expand Up @@ -116,19 +152,102 @@ def width(self, background=None, **kwargs):
for j in range(4):
_result = 0
for i in range(4):
y = (self.Q[to_fit, j] - self.position(**kwargs)[j]) ** 2 * (self.intensity[to_fit] - background)
y = (self.Q[to_fit, j] - self.position(**kwargs)[j]) ** 2 * \
(self.intensity[to_fit] - background)
_result += np.trapz(y, x=self.Q[to_fit, i]) / self.integrate(**kwargs)
result += (_result,)
else:
for j in range(4):
_result = 0
for i in range(4):
y = (self.Q[:, j] - self.position(**kwargs)[j]) ** 2 * (self.intensity - background)
y = (self.Q[:, j] - self.position(**kwargs)[j]) ** 2 * \
(self.intensity - background)
_result += np.trapz(y, x=self.Q[:, i]) / self.integrate(**kwargs)
result += (_result,)

return result

def scattering_function(self, material, ei):
r'''Returns the neutron scattering function, i.e. the detector counts
scaled by :math:`4 \pi / \sigma_{\mathrm{tot}} * k_i/k_f`.
Parameters
----------
material : object
Definition of the material given by the :py:class:`.Material`
class
ei : float
Incident energy in meV
Returns
-------
counts : ndarray
The detector counts scaled by the total scattering cross section
and ki/kf
'''
ki = Energy(energy=ei).wavevector
kf = Energy(energy=ei - self.e).wavevector

return (4 * np.pi / (material.total_scattering_cross_section) * ki /
kf * self.detector)

def dynamic_susceptibility(self, material, ei):
r'''Returns the dynamic susceptibility
:math:`\chi^{\prime\prime}(\mathbf{Q},\hbar\omega)`
Parameters
----------
material : object
Definition of the material given by the :py:class:`.Material`
class
ei : float
Incident energy in meV
Returns
-------
counts : ndarray
The detector counts turned into the scattering function multiplied
by the detailed balance factor
'''
return (self.scattering_function(material, ei) *
self.detailed_balance_factor)

def estimate_background(self, bg_params):
r'''Estimate the background according to ``type`` specified.
Parameters
----------
bg_params : dict
Input dictionary has keys 'type' and 'value'. Types are
* 'constant' : background is the constant given by 'value'
* 'percent' : background is estimated by the bottom x%, where x
is value
* 'minimum' : background is estimated as the detector counts
Returns
-------
background : float or ndarray
Value determined to be the background. Will return ndarray only if
`'type'` is `'constant'` and `'value'` is an ndarray
'''
if bg_params['type'] == 'constant':
return bg_params['value']

elif bg_params['type'] == 'percent':
inten = self.intensity[self.intensity >= 0.]
Npts = inten.size * (bg_params['value'] / 100.)
min_vals = inten[np.argsort(inten)[:Npts]]
background = np.average(min_vals)
return background

elif bg_params['type'] == 'minimum':
return min(self.intensity)

else:
return 0


class Data(PlotData, Analysis):
u'''Data class for handling multi-dimensional scattering data. If input
Expand Down Expand Up @@ -182,16 +301,16 @@ class Data(PlotData, Analysis):
Methods
-------
bin
combine_data
subtract_background
integrate
position
width
load_file
plot
estimate_background
subtract_background
dynamic_susceptibility
scattering_function
combine_data
plot
'''
def __init__(self, Q=None, h=0., k=0., l=0., e=0., temp=0.,
Expand Down Expand Up @@ -425,66 +544,6 @@ def error(self, value):
a float.'''.format(self.detector.shape[0]))
self._err = value

@property
def detailed_balance_factor(self):
r'''Returns the detailed balance factor (sometimes called the Bose
factor)
Parameters
----------
None
Returns
-------
dbf : ndarray
The detailed balance factor (temperature correction)
'''

return 1. - np.exp(-self.Q[:, 3] / BOLTZMANN_IN_MEV_K / self.temp)

def scattering_function(self, material, ei):
r'''Returns the neutron scattering function, i.e. the detector counts
scaled by :math:`4 \pi / \sigma_{\mathrm{tot}} * k_i/k_f`.
Parameters
----------
material : object
Definition of the material given by the :py:class:`.Material` class
ei : float
Incident energy in meV
Returns
-------
counts : ndarray
The detector counts scaled by the total scattering cross section and ki/kf
'''
ki = Energy(energy=ei).wavevector
kf = Energy(energy=ei - self.e).wavevector

return (4 * np.pi / (material.total_scattering_cross_section) * ki /
kf * self.detector)

def dynamic_susceptibility(self, material, ei):
r'''Returns the dynamic susceptibility :math:`\chi^{\prime\prime}(\mathbf{Q},\hbar\omega)`
Parameters
----------
material : object
Definition of the material given by the :py:class:`.Material` class
ei : float
Incident energy in meV
Returns
-------
counts : ndarray
The detector counts turned into the scattering function multiplied by the detailed balance factor
'''
return (self.scattering_function(material, ei) *
self.detailed_balance_factor)

def combine_data(self, *args, **kwargs):
r'''Combines multiple data sets
Expand Down Expand Up @@ -556,7 +615,8 @@ def subtract_background(self, background_data, ret=True):
Data object containing the data wishing to be subtracted
ret : bool, optional
Set False if background should be subtracted in place. Default:True
Set False if background should be subtracted in place.
Default: True
Returns
-------
Expand All @@ -566,40 +626,6 @@ def subtract_background(self, background_data, ret=True):
'''
pass

def estimate_background(self, bg_params):
r'''Estimate the background according to ``type`` specified.
Parameters
----------
bg_params : dict
Input dictionary has keys 'type' and 'value'. Types are
* 'constant' : background is the constant given by 'value'
* 'percent' : background is estimated by the bottom x%, where x
is value
* 'minimum' : background is estimated as the detector counts
Returns
-------
background : float or ndarray
Value determined to be the background. Will return ndarray only if
`'type'` is `'constant'` and `'value'` is an ndarray
'''
if bg_params['type'] == 'constant':
return bg_params['value']

elif bg_params['type'] == 'percent':
inten = self.intensity[self.intensity >= 0.]
Npts = inten.size * (bg_params['value'] / 100.)
min_vals = inten[np.argsort(inten)[:Npts]]
background = np.average(min_vals)
return background

elif bg_params['type'] == 'minimum':
return min(self.intensity)

else:
return 0

def _bin_parallel(self, Q_chunk):
r'''Performs binning by finding data chunks to bin together.
Private function for performing binning in parallel using
Expand Down Expand Up @@ -702,12 +728,14 @@ def bin(self, to_bin): # pylint: disable=unused-argument
Q = np.meshgrid(*q)
Q = np.vstack((item.flatten() for item in Q)).T

nprocs = cpu_count() # @UndefinedVariable
Q_chunks = [Q[n * Q.shape[0] // nprocs:(n + 1) * Q.shape[0] // nprocs] for n in range(nprocs)]
pool = Pool(processes=nprocs) # pylint: disable=not-callable
nprocs = cpu_count()
Q_chunks = [Q[n * Q.shape[0] // nprocs:(n + 1) * Q.shape[0] // nprocs]
for n in range(nprocs)]
pool = Pool(processes=nprocs)
outputs = pool.map(_call_bin_parallel, zip([self] * len(Q_chunks), Q_chunks))
pool.close()

monitor, detector, time, error = (np.concatenate(arg) for arg in zip(*outputs))

return Data(Q=Q, monitor=monitor, detector=detector, time=time, m0=self.m0, t0=self.t0, error=error)
return Data(Q=Q, monitor=monitor, detector=detector, time=time,
m0=self.m0, t0=self.t0, error=error)
11 changes: 6 additions & 5 deletions neutronpy/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ def build_Q(args, **kwargs):
Returns
-------
Q : ndarray
Returns **Q**\ (h, k, l, e, temp) with shape (N, 5) in a column oriented
array.
Returns **Q**\ (h, k, l, e, temp) with shape (N, 5) in a column
oriented array.
'''
return np.vstack((args[i].flatten() for i in
Expand All @@ -46,8 +46,8 @@ def load_data(files, filetype='auto', tols=1e-4):
determine the filetype automatically.
tols : float or array_like
Default: `1e-4`. A float or array of shape `(5,)` giving tolerances for
combining multiple files. If multiple points are within the given
Default: `1e-4`. A float or array of shape `(5,)` giving tolerances
for combining multiple files. If multiple points are within the given
tolerances then they will be combined into a single point. If a float
is given, tolerances will all be the same for all variables in **Q**.
If an array is given tolerances should be in the format
Expand Down Expand Up @@ -143,7 +143,8 @@ def load_data(files, filetype='auto', tols=1e-4):
skip_lines = i + 2
break

args = np.genfromtxt(filename, unpack=True, dtype=np.float64, skip_header=skip_lines, skip_footer=1)
args = np.genfromtxt(filename, unpack=True, dtype=np.float64,
skip_header=skip_lines, skip_footer=1)

else:
raise ValueError('Filetype not supported.')
Expand Down

0 comments on commit 20e2530

Please sign in to comment.