def __init__(self, shape=None, zrange=None, laser_wavelength=<NUM_LIT>,<EOL>zslab=<NUM_LIT:0.>, zscale=<NUM_LIT:1.0>, kfki=<NUM_LIT>, n2n1=<NUM_LIT>/<NUM_LIT>, alpha=<NUM_LIT>,<EOL>polar_angle=<NUM_LIT:0.>, pxsize=<NUM_LIT>, support_factor=<NUM_LIT:2>, normalize=False,<EOL>sigkf=<NUM_LIT:0.0>, nkpts=None, cutoffval=None, measurement_iterations=None,<EOL>k_dist='<STR_LIT>', use_J1=True, sph6_ab=None, global_zscale=False,<EOL>cutbyval=False, cutfallrate=<NUM_LIT>, cutedgeval=<NUM_LIT>,<EOL>pinhole_width=None, do_pinhole=False, *args, **kwargs):

self.pxsize = pxsize<EOL>self.polar_angle = polar_angle<EOL>self.support_factor = support_factor<EOL>self.normalize = normalize<EOL>self.measurement_iterations = measurement_iterations or <NUM_LIT:11><EOL>self.global_zscale = global_zscale<EOL>self.polychromatic = False<EOL>self.sigkf = sigkf<EOL>self.nkpts = nkpts<EOL>self.cutoffval = cutoffval<EOL>self.cutbyval = cutbyval<EOL>self.cutfallrate = cutfallrate<EOL>self.cutedgeval = cutedgeval<EOL>self.k_dist = k_dist<EOL>self.use_J1 = use_J1<EOL>self.do_pinhole = do_pinhole<EOL>if self.sigkf is not None:<EOL><INDENT>self.nkpts = self.nkpts or <NUM_LIT:3><EOL>self.polychromatic = True<EOL><DEDENT>elif self.nkpts is not None:<EOL><INDENT>self.sigkf = <NUM_LIT:0.0><EOL>self.polychromatic = True<EOL><DEDENT>else:<EOL><INDENT>self.sigkf = sigkf = <NUM_LIT:0.0><EOL>self.polychromatic = False<EOL><DEDENT>if (sph6_ab is not None) and (not np.isnan(sph6_ab)):<EOL><INDENT>self.use_sph6_ab = True <EOL><DEDENT>else:<EOL><INDENT>self.use_sph6_ab = False<EOL><DEDENT>if shape and zrange is None:<EOL><INDENT>zrange = (<NUM_LIT:0>, shape.shape[<NUM_LIT:0>])<EOL><DEDENT>self.zrange = zrange<EOL>params = [<EOL>'<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>', '<STR_LIT>',<EOL>'<STR_LIT>', '<STR_LIT>'<EOL>]<EOL>values = np.array([<EOL>kfki,   zslab,   zscale,   alpha,   n2n1,   laser_wavelength,<EOL>sigkf,    sph6_ab<EOL>])<EOL>if not self.polychromatic:<EOL><INDENT>ind = params.index('<STR_LIT>')<EOL>params.pop(ind)<EOL>values = np.delete(values, ind)<EOL><DEDENT>if not self.use_sph6_ab:<EOL><INDENT>ind = params.index('<STR_LIT>')<EOL>params.pop(ind)<EOL>values = np.delete(values, ind)<EOL><DEDENT>for i in range(len(params)):<EOL><INDENT>if params[i] is '<STR_LIT>' and self.global_zscale:<EOL><INDENT>continue<EOL><DEDENT>params[i] = '<STR_LIT>' + params[i]<EOL><DEDENT>super(ExactPSF, self).__init__(<EOL>*args, params=params, values=values, shape=shape, **kwargs<EOL>)<EOL>

Superclass for all the exact PSFs, i.e. any PSF that is based on
physical properties of the imaging system such as the laser
wavelength.

This PSF functions by calculating the local PSF for every z layer
in the image, and convolving each layer independently (numerically
the exact model of image formation).

Parameters
----------
shape : tuple
    Shape of the image in (z,y,x) pixel numbers (to be deprecated)

zrange : tuple
    range of z pixels over which we should calculate the psf, good pixels
    being zrange[0] <= z <= zrange[1]. currently must be set to the interior
    of the image, so [state.pad, state.image.shape[0] - state.pad]

laser_wavelength : float
    wavelength of light in um of the incoming laser light

zslab : float
    Pixel position of the optical interface where 0 is the edge of the
    image in the z direction

zscale : float
    Scaling of the z pixel size, so that each pixel is located at
    zscale*(z - zint), such that the interface does not move with zscale

kfki : float
    Ratio of outgoing to incoming light wavevectors, 2\pi/\lambda

n2n1 : float
    Ratio of the index mismatch across the optical interface. For typical
    glass with glycerol/water 80/20 mixture this is 1.4/1.518

alpha : float
    Aperture of the lens in radians, set by arcsin(n2n1)?

polar_angle : float
    the angle of the light polarization with respect to the scanning axis

pxsize : float
    the size of a xy pixel in um, defaults to cohen group size 0.125 um

support_factor : integer
    size of the support

normalize : boolean
    if True, use the normalization as calculated by the PSF instead of
    unit normalization

sigkf : float
    Width of wavelengths to use in the polychromatic psf, None is
    monochromatic. Values for kfki = kfki +- sigkf, unitless

nkpts : integer
    number of integration points to use for the polychromatic psf

cutoffval : float
    Percentage of peak psf value to cutoff using a 3-axis
    exp(-(r-r0)**4) function where r0 is determined by cutoffval. A
    good value for this is the bit depth of the camera, or possibly the
    SNR, so 1/2**8 or 1/50.

measurement_iterations : int
    number of interations used when trying to find the center of mass
    of the psf in a certain slice

k_dist : str
    Eithe ['gaussian', 'gamma'] which control the wavevector
    distribution for the polychromatic detection psf. Default
    is Gaussian.

use_J1 : boolean
    Which hdet confocal model to use. Set to True to include the
    J1 term corresponding to a large-NA focusing lens, False to
    exclude it. Default is True

cutbyval : boolean
    If True, cuts the PSF based on the actual value instead of the
    position associated with the nearest value.

cutfallrate : float
    The relative value of the cutoffval over which to damp the
    remaining values of the psf. 0.3 seems a good fit now.

cutedgeval : float
    The value with which to determine the edge of the psf, typically
    taken around floating point, 1e-12

pinhole_width : Float
    The width of the line illumination, in 1/k units. Default is 1.0.

do_pinhole : Bool
    Whether or not to include pinhole line width in the sampling.
    Default is False.


return np.polyval(self.drift_poly, z)<EOL>

Give the pixel offset at a given z value for the current parameters


def __init__(self, shape=None, zrange=None, laser_wavelength=<NUM_LIT>, zslab=<NUM_LIT:0.>,<EOL>zscale=<NUM_LIT:1.0>, kfki=<NUM_LIT>, n2n1=<NUM_LIT>/<NUM_LIT>, alpha=<NUM_LIT>, polar_angle=<NUM_LIT:0.>,<EOL>pxsize=<NUM_LIT>, support_factor=<NUM_LIT:2>, normalize=False, sigkf=<NUM_LIT:0.0>,<EOL>nkpts=None, cutoffval=None, measurement_iterations=None,<EOL>k_dist='<STR_LIT>', use_J1=True, sph6_ab=None, global_zscale=False,<EOL>cutbyval=False, cutfallrate=<NUM_LIT>, cutedgeval=<NUM_LIT>,<EOL>*args, **kwargs):

super(ExactPinholeConfocalPSF, self).__init__(shape=shape,<EOL>zrange=zrange, laser_wavelength=laser_wavelength, zslab=zslab,<EOL>zscale=zscale, kfki=kfki, n2n1=n2n1, alpha=alpha, pxsize=<EOL>pxsize, polar_angle=polar_angle, support_factor=support_factor,<EOL>normalize=normalize, sigkf=sigkf, nkpts=nkpts, cutoffval=<EOL>cutoffval, measurement_iterations= measurement_iterations,<EOL>k_dist=k_dist, use_J1=use_J1, sph6_ab=sph6_ab, global_zscale=<EOL>global_zscale, cutbyval=cutbyval, cutfallrate=cutfallrate,<EOL>cutedgeval=cutedgeval, *args, **kwargs)<EOL>

PSF for a pinhole confocal microscopes that can be used with the
peri framework.  Calculates the spatially varying point spread
function for confocal microscopes and allows them to be applied to
images as a convolution.

This PSF assumes that the z extent is large compared to the image size
and so calculates the local PSF for every z layer in the image.

Parameters
----------
shape : tuple
    Shape of the image in (z,y,x) pixel numbers (to be deprecated)

zrange : tuple
    range of z pixels over which we should calculate the psf, good pixels
    being zrange[0] <= z <= zrange[1]. currently must be set to the interior
    of the image, so [state.pad, state.image.shape[0] - state.pad]

laser_wavelength : float
    wavelength of light in um of the incoming laser light

zslab : float
    Pixel position of the optical interface where 0 is the edge of the
    image in the z direction

zscale : float
    Scaling of the z pixel size, so that each pixel is located at
    zscale*(z - zint), such that the interface does not move with zscale

kfki : float
    Ratio of outgoing to incoming light wavevectors, 2\pi/\lambda

n2n1 : float
    Ratio of the index mismatch across the optical interface. For typical
    glass with glycerol/water 80/20 mixture this is 1.4/1.518

alpha : float
    Aperture of the lens in radians, set by arcsin(n2n1)?

polar_angle : float
    the angle of the light polarization with respect to the scanning axis

pxsize : float
    the size of a xy pixel in um, defaults to cohen group size 0.125 um

support_factor : integer
    size of the support

normalize : boolean
    if True, use the normalization as calculated by the PSF instead of
    unit normalization

sigkf : float
    Width of wavelengths to use in the polychromatic psf, None is
    monochromatic. Values for kfki = kfki +- sigkf, unitless

nkpts : integer
    number of integration points to use for the polychromatic psf

cutoffval : float
    Percentage of peak psf value to cutoff using a 3-axis
    exp(-(r-r0)**4) function where r0 is determined by cutoffval. A
    good value for this is the bit depth of the camera, or possibly the
    SNR, so 1/2**8 or 1/50.

measurement_iterations : int
    number of interations used when trying to find the center of mass
    of the psf in a certain slice

k_dist : str
    Eithe ['gaussian', 'gamma'] which control the wavevector
    distribution for the polychromatic detection psf. Default
    is Gaussian.

use_J1 : boolean
    Which hdet confocal model to use. Set to True to include the
    J1 term corresponding to a large-NA focusing lens, False to
    exclude it. Default is True

cutbyval : boolean
    If True, cuts the PSF based on the actual value instead of the
    position associated with the nearest value.

cutfallrate : float
    The relative value of the cutoffval over which to damp the
    remaining values of the psf. 0.3 seems a good fit now.

cutedgeval : float
    The value with which to determine the edge of the psf, typically
    taken around floating point, 1e-12

Notes:
    a = ExactLineScanConfocalPSF((64,)*3)
    psf, (z,y,x) = a.psf_slice(1., size=51)
    imshow((psf*r**4)[:,:,25], cmap='bone')


mapper = {<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': '<STR_LIT>'<EOL>}<EOL>bads = [self.zscale, '<STR_LIT>']<EOL>d = {}<EOL>for k,v in iteritems(mapper):<EOL><INDENT>if k in self.param_dict:<EOL><INDENT>d[v] = self.param_dict[k]<EOL><DEDENT><DEDENT>d.update({<EOL>'<STR_LIT>': self.polar_angle,<EOL>'<STR_LIT>': self.normalize,<EOL>'<STR_LIT>':self.use_J1<EOL>})<EOL>if self.polychromatic:<EOL><INDENT>d.update({'<STR_LIT>': self.nkpts})<EOL>d.update({'<STR_LIT>': self.k_dist})<EOL><DEDENT>if self.do_pinhole:<EOL><INDENT>d.update({'<STR_LIT>': self.num_line_pts})<EOL><DEDENT>d.update({'<STR_LIT>': True})<EOL>return d<EOL>

Pack the parameters into the form necessary for the integration
routines above.  For example, packs for calculate_linescan_psf


for c in self.comps:<EOL><INDENT>c.set_shape(shape, inner)<EOL><DEDENT>


return {<EOL>'<STR_LIT>': self.comps,<EOL>'<STR_LIT>': self.category,<EOL>'<STR_LIT>': self.field_reduce_func,<EOL>}<EOL>

Return arguments that are passed to init to setup the class again


pass<EOL>


return {"<STR_LIT>": self.params, "<STR_LIT>": self.values, "<STR_LIT>": self.ordered}<EOL>

Pickling helper method which returns a dictionary of function
parameters which get passed to pickle via `__getinitargs__
<https://docs.python.org/2/library/pickle.html#object.__getinitargs__>`_

Returns
-------
arg_dict : dictionary
    ``**kwargs`` to be passed to the __init__ func after unpickling


def _normalize(comps, param):<EOL><INDENT>vals = [c.get_values(param) for c in comps]<EOL>diff = any([vals[i] != vals[i+<NUM_LIT:1>] for i in range(len(vals)-<NUM_LIT:1>)])<EOL>if diff:<EOL><INDENT>for c in comps:<EOL><INDENT>c.set_values(param, vals[<NUM_LIT:0>])<EOL><DEDENT><DEDENT><DEDENT>for param, comps in iteritems(self.lmap):<EOL><INDENT>if isinstance(comps, list) and len(comps) > <NUM_LIT:1>:<EOL><INDENT>_normalize(comps, param)<EOL><DEDENT><DEDENT>

Ensure that shared parameters are the same value everywhere


for c in self.comps:<EOL><INDENT>c.set_tile(tile)<EOL><DEDENT>

Set the current working tile for components


def split_params(self, params, values=None):

pc, vc = [], []<EOL>returnvalues = values is not None<EOL>if values is None:<EOL><INDENT>values = [<NUM_LIT:0>]*len(util.listify(params))<EOL><DEDENT>for c in self.comps:<EOL><INDENT>tp, tv = [], []<EOL>for p,v in zip(util.listify(params), util.listify(values)):<EOL><INDENT>if not p in self.lmap:<EOL><INDENT>raise NotAParameterError("<STR_LIT>" % (p, self))<EOL><DEDENT>if c in self.pmap[p]:<EOL><INDENT>tp.append(p)<EOL>tv.append(v)<EOL><DEDENT><DEDENT>pc.append(tp)<EOL>vc.append(tv)<EOL><DEDENT>if returnvalues:<EOL><INDENT>return pc, vc<EOL><DEDENT>return pc<EOL>

Split params, values into groups that correspond to the ordering in
self.comps. For example, given a sphere collection and slab::

    [
        (spheres) [pos rad etc] [pos val, rad val, etc]
        (slab) [slab params] [slab vals]
    ]


def get_update_tile(self, params, values):

pass<EOL>

This method returns a :class:`~peri.util.Tile` object defining the
region of a field that has to be modified by the update of (params,
values). For example, if this Component is the point-spread-function,
it might return a tile of entire image since every parameter affects
the entire image::

    return self.shape

Parameters
-----------
params : single param, list of params
    A single parameter or list of parameters to be updated

values : single value, list of values
    The values corresponding to the params

Returns
-------
tile : :class:`~peri.util.Tile`
    A tile corresponding to the image region


self._parent = obj<EOL>

Registery a parent object so that communication maybe happen upwards


fields = [c.get() for c in self.comps]<EOL>return self.field_reduce_func(fields)<EOL>


pass<EOL>

Return the `natural` part of the model. In the case of most elements it
is the calculated field, for others it is the object itself.


def trigger_update(self, params, values):

if self._parent:<EOL><INDENT>self._parent.trigger_update(params, values)<EOL><DEDENT>else:<EOL><INDENT>self.update(params, values)<EOL><DEDENT>


def __init__(self, params, values, ordered=True, category='<STR_LIT>'):

for attr in ['<STR_LIT>', '<STR_LIT>', '<STR_LIT>']:<EOL><INDENT>if not hasattr(self, attr):<EOL><INDENT>setattr(self, attr, None)  <EOL><DEDENT><DEDENT>super(Component, self).__init__(<EOL>params, values, ordered=ordered, category=category<EOL>)<EOL>

A :class:`~peri.comp.comp.ParameterGroup` which specifically computes
over sections of an image for an :class:`~peri.states.ImageState`. To
this end, we require the implementation of several new member functions:

    * :func:`~peri.comp.comp.Component.initialize`
    * :func:`~peri.comp.comp.Component.get_update_tile`
    * :func:`~peri.comp.comp.Component.get_padding_size`
    * :func:`~peri.comp.comp.Component.set_shape`
    * :func:`~peri.comp.comp.Component.set_tile`
    * :func:`~peri.comp.comp.Component.get`

In order to facilitate optimizations such as caching and local updates,
we must incorporate tiling in this object.

Parameters
----------
params : string, list of strings
    The names of the parameters, in the proper order

values : number, list of numbers
    The values corresponding to the parameter names

ordered : boolean (default: True)
    If True, uses an OrderedDict so that parameter order is
    deterministic independent of number of parameters

category : string (default: 'param')
    Name of the category associated with this ParameterGroup.


return []<EOL>

Elements of the class that should not be included in pickled objects.
If inheriting a new class, should be::

    super(Class, self).nopickle() + ['other1', 'other2', ...]

Returns
-------
elements : list of strings
    The name of class member variables which should not be pickled


pass<EOL>

Perform its routine, whatever that may be


if self._parent:<EOL><INDENT>self._parent.trigger_parameter_change()<EOL><DEDENT>


def __init__(self, pos, shape=None, param_prefix='<STR_LIT>', category='<STR_LIT>',<EOL>support_pad=<NUM_LIT:4>, float_precision=np.float64):

if pos.ndim != <NUM_LIT:2>:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>self.category = category<EOL>self.support_pad = support_pad<EOL>self.pos = pos.astype('<STR_LIT:float>')<EOL>self.param_prefix = param_prefix<EOL>if float_precision not in (np.float64, np.float32, np.float16):<EOL><INDENT>raise ValueError('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL><DEDENT>self.float_precision = float_precision<EOL>self.shape = shape<EOL>self.setup_variables()<EOL>if self.shape:<EOL><INDENT>self.inner = self.shape.copy()<EOL>self.tile = self.inner.copy()<EOL>self.initialize()<EOL><DEDENT>

Parent class for a large collection of particles, such as spheres or
points or ellipsoids or rods.

This class is good for a collection of objects which each have a
position as well as (possibly) some other parameters, like particle
radius, aspect ratio, or brightness. Its .get() method returns a
field of the drawn particles, selected on the current tile. Any
daughter classes need the following methods:

* _draw_particle
* _update_type
* setup_variables
* get_values
* set_values
* add_particle
* remove_particle

In addition, the following methods should be modified for particles
with more parameters than just positions:

* _drawargs
* _tile
* param_particle
* exports
* _p2i

If you have a few objects to group, like 2 or 3 slabs, group them
with a `peri.comp.ComponentCollection` instead.

Parameters
----------
pos : ndarray [N,d]
    Initial positions of the particles. Re-cast as float internally

shape : ``peri.util.Tile``, optional
    Shape of the field over which to draw the platonic spheres.
    Default is None.

param_prefix : string, optional
    Prefix for the particle parameter names. Default is `'sph'`

category : string, optional
    Category, as in comp.Component. Default is `'obj'`.

support_pad : Int, optional
    How much to pad the boundary of particles when calculating the
    support so that particles do not leak out the edges. Default is 4

float_precision : numpy float datatype, optional
    One of numpy.float16, numpy.float32, numpy.float64; precision
    for precomputed arrays. Default is np.float64; make it 16 or 32
    to save memory.


raise NotImplementedError('<STR_LIT>')<EOL>

Given a list of parameters, returns a bool of whether or not any of
the parameters require a global update, and a list of particle indices
which are included in ``params``, e.g.
``return doglobal, particles``


return '<STR_LIT:->'.join([self.param_prefix, str(ind), coord])<EOL>


def __init__(self, zpos=<NUM_LIT:0>, angles=(<NUM_LIT:0>,<NUM_LIT:0>), param_prefix='<STR_LIT>', shape=None,<EOL>float_precision=np.float64, category='<STR_LIT>'):

self.lbl_zpos = param_prefix+'<STR_LIT>'<EOL>self.lbl_theta = param_prefix+'<STR_LIT>'<EOL>self.lbl_phi = param_prefix+'<STR_LIT>'<EOL>if float_precision not in (np.float64, np.float32, np.float16):<EOL><INDENT>raise ValueError('<STR_LIT>' +<EOL>'<STR_LIT>')<EOL><DEDENT>self.float_precision = float_precision<EOL>params = [self.lbl_zpos, self.lbl_theta, self.lbl_phi]<EOL>values = [float(i) for i in [zpos, angles[<NUM_LIT:0>], angles[<NUM_LIT:1>]]]<EOL>super(Slab, self).__init__(params, values, ordered=False,<EOL>category=category)<EOL>if shape:<EOL><INDENT>inner = shape.copy()  <EOL>self.set_shape(shape, inner)<EOL><DEDENT>self.set_tile(self.shape)<EOL>if self.shape:<EOL><INDENT>self.initialize()<EOL><DEDENT>

A half plane corresponding to a cover-slip.

Parameters
----------
shape : tuple
    field shape over which to calculate

zpos : float
    position of the center of the slab in pixels

angles : tuple of float (2,), optional
    Euler-like Angles of rotation of the normal with respect to the
    z-axis, i.e. ``angles=(0., 0.)`` gives a slab with a normal
    along z. The first angle theta is the rotation about the x-axis;
    the second angle phi is the rotation about the y-axis. Default
    is (0,0).

float_precision : numpy float datatype
    One of numpy.float16, numpy.float32, numpy.float64; precision
    for precomputed arrays. Default is np.float64; make it 16 or 32
    to save memory.


def sphere_constrained_cubic(dr, a, alpha):

sqrt3 = np.sqrt(<NUM_LIT:3>)<EOL>b_coeff = a*<NUM_LIT:0.5>/sqrt3*(<NUM_LIT:1> - <NUM_LIT>*sqrt3*alpha)/(<NUM_LIT> + a*a)<EOL>rscl = np.clip(dr, -<NUM_LIT:0.5>*sqrt3, <NUM_LIT:0.5>*sqrt3)<EOL>a, d = rscl + <NUM_LIT:0.5>*sqrt3, rscl - <NUM_LIT:0.5>*sqrt3<EOL>return alpha*d*a*rscl + b_coeff*d*a - d/sqrt3<EOL>

Sphere generated by a cubic interpolant constrained to be (1,0) on
(r0-sqrt(3)/2, r0+sqrt(3)/2), the size of the cube in the (111) direction.


return [self._i2p(i, '<STR_LIT:a>') for i in range(self.N)]<EOL>


return (<NUM_LIT:1>-np.clip((dr+alpha) / (<NUM_LIT:2>*alpha), <NUM_LIT:0>, <NUM_LIT:1>))<EOL>

Linearly interpolate the pixels for the platonic object


ind = self._vps(listify(ind))<EOL>return [self._i2p(i, j) for i in ind for j in ['<STR_LIT:z>', '<STR_LIT:y>', '<STR_LIT:x>']]<EOL>


<EOL>global_update, particles = self._update_type(params)<EOL>if global_update:<EOL><INDENT>self.set_values(params, values)<EOL>self.initialize()<EOL>return<EOL><DEDENT>oldargs = self._drawargs()<EOL>for n in particles:<EOL><INDENT>self._draw_particle(self.pos[n], *listify(oldargs[n]), sign=-<NUM_LIT:1>)<EOL><DEDENT>self.set_values(params, values)<EOL>newargs = self._drawargs()<EOL>for n in particles:<EOL><INDENT>self._draw_particle(self.pos[n], *listify(newargs[n]), sign=+<NUM_LIT:1>)<EOL><DEDENT>

Update the particles field given new parameter values


<EOL>params = listify(params)<EOL>values = listify(values)<EOL>for i, p in enumerate(params):<EOL><INDENT>if (p[-<NUM_LIT:2>:] == '<STR_LIT>') and (values[i] < <NUM_LIT:0>):<EOL><INDENT>values[i] = <NUM_LIT:0.0><EOL><DEDENT><DEDENT>super(PlatonicSpheresCollection, self).update(params, values)<EOL>

Calls an update, but clips radii to be > 0


def _draw_particle(self, pos, sign=<NUM_LIT:1>):

Updates ``self.particles`` by drawing a particle at position ``pos``,
with possible additional unnamed arguments between ``pos`` and
``sign``. If ``sign`` is -1, un-draws the particle instead.

To be able to fit this component in a model, _draw_particle must
create an image that is numerically continuous as pos changes --
i.e. the edge of the particle must alias smoothly to 0.


dozscale = False<EOL>particles = []<EOL>for p in listify(params):<EOL><INDENT>typ, ind = self._p2i(p)<EOL>particles.append(ind)<EOL>dozscale = dozscale or typ == '<STR_LIT>'<EOL><DEDENT>particles = set(particles)<EOL>return dozscale, particles<EOL>

Returns dozscale and particle list of update


pos = self._trans(self.pos[n])<EOL>return Tile(pos, pos).pad(self.support_pad)<EOL>

Get the update tile surrounding particle `n`


ind = self._vps(listify(ind))<EOL>return [self._i2p(i, '<STR_LIT:a>') for i in ind]<EOL>


return [j for j in inds if j >= <NUM_LIT:0> and j < self.N]<EOL>

Clips a list of inds to be on [0, self.N]


<EOL>raise NotImplementedError('<STR_LIT>')<EOL>

Returns a util.delisty-d assortment of values and parameters, e.g.
(get values for the parameters, both particle positions and globals)
(return delistify(values, params))


return self.param_particle_pos(list(range(self.N)))<EOL>


<EOL>ind = self._vps(listify(ind))<EOL>return [self._i2p(i, j) for i in ind for j in ['<STR_LIT:z>', '<STR_LIT:y>', '<STR_LIT:x>']]<EOL>


def exact_volume_sphere(rvec, pos, radius, zscale=<NUM_LIT:1.0>, volume_error=<NUM_LIT>,<EOL>function=sphere_analytical_gaussian, max_radius_change=<NUM_LIT>, args=()):

vol_goal = <NUM_LIT>/<NUM_LIT:3>*np.pi*radius**<NUM_LIT:3> / zscale<EOL>rprime = radius<EOL>dr = inner(rvec, pos, rprime, zscale=zscale)<EOL>t = function(dr, rprime, *args)<EOL>for i in range(MAX_VOLUME_ITERATIONS):<EOL><INDENT>vol_curr = np.abs(t.sum())<EOL>if np.abs(vol_goal - vol_curr)/vol_goal < volume_error:<EOL><INDENT>break<EOL><DEDENT>rprime = rprime + <NUM_LIT:1.0>*(vol_goal - vol_curr) / (<NUM_LIT:4>*np.pi*rprime**<NUM_LIT:2>)<EOL>if np.abs(rprime - radius)/radius > max_radius_change:<EOL><INDENT>break<EOL><DEDENT>dr = inner(rvec, pos, rprime, zscale=zscale)<EOL>t = function(dr, rprime, *args)<EOL><DEDENT>return t<EOL>

Perform an iterative method to calculate the effective sphere that perfectly
(up to the volume_error) conserves volume.  Return the resulting image


return [[] for p in self.pos]<EOL>

Returns a list of arguments for self._draw_particle, of the same
length as `self.pos`. For example, if drawing a sphere, _drawargs
could return a list of radii.


return (((self.pos - x)**<NUM_LIT:2>).sum(axis=-<NUM_LIT:1>)).argmin()<EOL>

Get the index of the particle closest to vector `x`


def step(self, steps=<NUM_LIT:100>, mask=None):

if mask is None:<EOL><INDENT>mask = np.ones_like(self.rad).astype('<STR_LIT:bool>')<EOL><DEDENT>for step in range(steps):<EOL><INDENT>self.forces = self.force_hardsphere(mask) + self.force_noise()<EOL>self.forces[~mask, :] = <NUM_LIT:0.><EOL>self.integrate(self.forces)<EOL>self.boundary_condition()<EOL><DEDENT>

Perform a set of integration / BC steps and update plot

Parameters:
-----------
steps : int
    number of time steps of size self.dt to perform

mask : boolean ndarray[N]
    if provided, only simulate the motion of certain particles given
    by the boolean array mask


def create_configuration(N, tile, radius=<NUM_LIT>, **kwargs):

pos, rad, tile = initialize_particles(N, tile, radius=radius, **kwargs)<EOL>sim = BrownianHardSphereSimulation(pos, rad, tile)<EOL>sim.relax(<NUM_LIT:1000>)<EOL>sim.step(<NUM_LIT:1000>)<EOL>sim.relax(<NUM_LIT:1000>)<EOL>return sim.pos, sim.rad, tile<EOL>

Quick configuration creation with `N` particles in a tile of size `tile`.


def __init__(self, pos, rad, tile, D=<NUM_LIT>, epsilon=<NUM_LIT>, dt=<NUM_LIT>):

self.pos = pos<EOL>self.rad = rad<EOL>self.tile = tile<EOL>self.N = self.pos.shape[<NUM_LIT:0>]<EOL>self.dim = self.pos.shape[<NUM_LIT:1>]<EOL>self.forces = <NUM_LIT:0>*self.pos<EOL>self.D = D<EOL>self.dt = dt<EOL>self.epsilon = epsilon<EOL>

Creates a hard sphere brownian dynamics simulation in ND as specified
by the pos, rad and tile supplied to initializer.

Parameters:
-----------
pos : ndarray [N, dim]
    Positions of particles in the simulation.

rad : ndarray [N]
    Radii of particles in the simulation.

tile : `peri.util.Tile`
    The simulation box defined by a tile with left and right bounds.

D : float
    diffusion constant in proper units

epsilon : float
    Force constant for the soft-sphere potential f = \epsilon (1-d/d_0)^{3/2}.
    This parameter is really a ratio of epsilon / eta (the damping parameter)

dt : float
    timestep for the integrator


coeff = np.sqrt(<NUM_LIT:2>*self.D)<EOL>return coeff * np.random.randn(*self.pos.shape)<EOL>

Calculate the effective force of the Langevin dynamics


ind = df['<STR_LIT>'] == particle_ind<EOL>rads = np.array(df['<STR_LIT>'][ind].copy())<EOL>z = np.array(df['<STR_LIT:z>'][ind].copy())<EOL>x = np.array(df['<STR_LIT:x>'][ind].copy())<EOL>y = np.array(df['<STR_LIT:y>'][ind].copy())<EOL>return x,y,z,rads<EOL>

Returns the x,y,z, radii values of a dataframe for a given particle index.

Parameters
----------
    df : DataFrame
    particle_ind : Int
Returns
-------
    x, y, z, rads : numpy.ndarray


def calculate_state_radii_fluctuations(state_list, inbox=True, fullinbox=True,<EOL>inboxrad=False, maxdisp=<NUM_LIT>, threshold=None, return_all=False):

pos, rad = [], []<EOL>for s in state_list:<EOL><INDENT>m = analyze.good_particles(s, inbox=inbox, inboxrad=inboxrad,<EOL>fullinbox=fullinbox)<EOL>pos.append(s.obj_get_positions()[m])<EOL>rad.append(s.obj_get_radii()[m])<EOL><DEDENT>df = track(pos, rad, maxdisp=maxdisp, threshold=threshold)<EOL>zyxr_t = []<EOL>for i in np.unique(df['<STR_LIT>']):<EOL><INDENT>x,y,z,r = get_xyzr_t(df, <NUM_LIT:1>*i)<EOL>if z.size > <NUM_LIT:1>:<EOL><INDENT>zyxr_t.append([x.mean(), y.mean(), z.mean(), r.mean(), r.std()])<EOL><DEDENT><DEDENT>z, y, x, rm, rs = np.transpose(zyxr_t)<EOL>if return_all:<EOL><INDENT>return z, y, x, rm, rs<EOL><DEDENT>else:<EOL><INDENT>return rs<EOL><DEDENT>

Calculates the radii fluctuations throughout a series of images.

Parameters
----------
    state_list : iterable
        List or any iterator/generator of peri.states objects to analyze.

    inbox : Bool
        Set to False to include all particles, not just the ones in the
        image. Default is True (only particles in image).
    fullinbox : Bool
        Set to True to only include particles which are
    inboxrad : Bool
        Set to True to include all particles which overlap at all with the
        image. Default False

    maxdisp : Float
        The maximum displacement a particle can do between frames.
    threshold : Int
        Threshold for trackpy.filter_stubs

    return_all : Bool
        Set to True to return the mean z,y,x,r for all the particles
        as well as r.std(). Default is False (just returns r.std()

Returns
-------
    [z,] : np.ndarray
        The mean z-positions of each particle. Returned if `return_all`
        is True.
    [y,] : np.ndarray
        The mean y-positions of each particle. Returned if `return_all`
        is True.
    [x,] : np.ndarray
        The mean x-positions of each particle. Returned if `return_all`
        is True.
    [rm,] : np.ndarray
        The mean radii of each particle. Returned if `return_all` is
        True.
    rs : np.ndarray
        The standard deviation of each particle's radius across all
        states.


import argparse<EOL>import beanstalkc as bean<EOL>parser = argparse.ArgumentParser(description="<STR_LIT>")<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', type=int, help="<STR_LIT>")<EOL>parser.add_argument('<STR_LIT>', '<STR_LIT>', type=int, help="<STR_LIT>")<EOL>args = vars(parser.parse_args())<EOL>port = int(args.get('<STR_LIT:port>') or DEFAULT_BEANSTALKD)<EOL>proc = int(args.get('<STR_LIT>') or <NUM_LIT:1>)<EOL>def _listen(func, index):<EOL><INDENT>sys.stdout = open('<STR_LIT>'.format(index), "<STR_LIT:w>", buffering=<NUM_LIT:0>)<EOL>sys.stderr = open('<STR_LIT>'.format(index), "<STR_LIT:w>", buffering=<NUM_LIT:0>)<EOL>bsd = bean.Connection(host=LOCALHOST, port=port)<EOL>while True:<EOL><INDENT>job = bsd.reserve()<EOL>func(json.loads(job.body))<EOL><DEDENT><DEDENT>log.info('<STR_LIT>')<EOL>for i in range(proc):<EOL><INDENT>log.info('<STR_LIT:{}>'.format(i))<EOL>Process(target=_listen, args=(func,i)).start()<EOL><DEDENT>

This function is for use in external scripts in order to listen on the
queue and perform tasks. In particular, create a function which takes the
arguments you would pass to `launch_all`s jobs parameter, then at the
bottom of the script add:

if __name__ == '__main__':
    peri.test.beanstalk.listen(my_function_name)


return - self.beta * self.vel<EOL>


for i in range(self.dim):<EOL><INDENT>mask = (self.pos[:,i] < <NUM_LIT:0>)<EOL>self.pos[mask,i] = <NUM_LIT:2>*<NUM_LIT:0>-self.pos[mask,i]<EOL>self.vel[mask,i] *= -<NUM_LIT:1><EOL>mask = (self.pos[:,i] > self.box[i])<EOL>self.pos[mask,i] = <NUM_LIT:2>*self.box[i]-self.pos[mask,i]<EOL>self.vel[mask,i] *= -<NUM_LIT:1><EOL><DEDENT>

Apply hard reflective boundary conditions to particles


for step in range(steps):<EOL><INDENT>self.forces = self.force_hertzian() + self.force_damp() + self.force_noise()<EOL>self.integrate(self.forces)<EOL>self.boundary_condition()<EOL><DEDENT>

Perform a set of integration / BC steps including finite temperature

Parameters:
-----------
steps : int
    number of time steps of size self.dt to perform


for step in range(steps):<EOL><INDENT>self.forces = self.force_hertzian() + self.force_damp()<EOL>self.integrate(self.forces)<EOL>self.boundary_condition()<EOL><DEDENT>

Relax the current configuration using just pair wise forces (no noise)


def __init__(self, N=<NUM_LIT>, phi=<NUM_LIT>, radius=<NUM_LIT>, polydispersity=<NUM_LIT:0.0>, beta=<NUM_LIT:1>,<EOL>epsilon=<NUM_LIT>, T=<NUM_LIT:1>, dt=<NUM_LIT>, dim=<NUM_LIT:3>, box_side_ratio=<NUM_LIT:1.0>):

self.N = N<EOL>self.phi = phi<EOL>self.beta = beta<EOL>self.epsilon = epsilon<EOL>self.T = T<EOL>self.dt = dt<EOL>self.radius = radius<EOL>self.polydispersity = polydispersity<EOL>self.box_side_ratio = box_side_ratio<EOL>self.dim = int(dim)<EOL>if self.dim == <NUM_LIT:2>:<EOL><INDENT>self.box_side = (self.N*np.pi*self.radius**<NUM_LIT:2> / self.phi)**(<NUM_LIT:1.>/<NUM_LIT:2>)<EOL>self.box = np.array([self.box_side]*self.dim)<EOL><DEDENT>if self.dim == <NUM_LIT:3>:<EOL><INDENT>self.box_side = (self.N*<NUM_LIT>/<NUM_LIT:3>*np.pi*self.radius**<NUM_LIT:3> / self.phi)**(<NUM_LIT:1.>/<NUM_LIT:3>)<EOL>sxy = self.box_side/np.sqrt(self.box_side_ratio)<EOL>sz  = self.box_side*self.box_side_ratio<EOL>self.box = np.array([sz, sxy, sxy])<EOL><DEDENT>self.init_random()<EOL>

Creates a simulation of soft sphere particles. By default, creates
particles in a random uniform (perhaps overlapping) distribution of
particles inside a box dimension `dim` given a packing fraction

Parameters:
-----------
N : integer [default: 500]
    the number of particles in the simulation

phi : float
    packing fraction to use while initializing the particles

radius : float [default: 5]
    mean radius of the particles, see polydispersity

polydispersity : float [default: 0]
    relative polydispersity goal sqrt(<(a-<a>)^2>)/<a>

beta : float
    damping parameter f = -beta v

epsilon : float
    force constant for the soft-sphere potential f = \epsilon (1-d/d_0)^{3/2}

T : float
    temperature of the system

dt : float
    timestep for the integrator

dim : integer [default: 3]
    number of dimensions for the simulation

box_side_ratio : float [default: 1]
    ratio of the box's z height to original z height before scaling.
    therefore, you can squish the box by half (while elongating the
    sides) by setting box_side_ratio=0.5


self.vel += forces*self.dt<EOL>self.pos += self.vel*self.dt<EOL>

Integrate the equations of motion. For this simple integrator, we are
using the simplest sympletic integrator, NSV where

    v_{n+1} = v_n + f*dt
    x_{n+1} = x_n + v_{n+1}*dt

Parameters:
-----------
forces : ndarray[N,dim]
    the forces on each particle


def create_single_particle_state(imsize, radius=<NUM_LIT>, seed=None, **kwargs):

_seed_or_not(seed)<EOL>imsize = _toarr(imsize)<EOL>pos = imsize.reshape(-<NUM_LIT:1>,<NUM_LIT:3>)/<NUM_LIT><EOL>rad = radius<EOL>return create_state(util.NullImage(shape=imsize), pos, rad, **kwargs)<EOL>

Creates a single particle state

Parameters:
-----------
imsize : tuple, array_like, or integer
    the unpadded image size to fill with particles

radius : float
    radius of particles to add

seed : integer
    set the seed if desired

*args, **kwargs : see create_state


def create_two_particle_state(imsize, radius=<NUM_LIT>, delta=<NUM_LIT:1.0>, seed=None, axis='<STR_LIT:x>', **kwargs):

_seed_or_not(seed)<EOL>imsize = _toarr(imsize)<EOL>comp = {'<STR_LIT:x>': <NUM_LIT:2>, '<STR_LIT:y>': <NUM_LIT:1>, '<STR_LIT:z>': <NUM_LIT:0>}<EOL>t = float(radius)+float(delta)/<NUM_LIT:2><EOL>d = np.array([<NUM_LIT:0.0>, <NUM_LIT:0.0>, <NUM_LIT:0.0>])<EOL>d[comp[axis]] = t<EOL>pos = np.array([imsize/<NUM_LIT> - d, imsize/<NUM_LIT> + d]).reshape(-<NUM_LIT:1>,<NUM_LIT:3>)<EOL>rad = np.array([radius, radius])<EOL>return create_state(util.NullImage(shape=imsize), pos, rad, **kwargs)<EOL>

Creates a two particle state

Parameters:
-----------
imsize : tuple, array_like, or integer
    the unpadded image size to fill with particles

radius : float
    radius of particles to add

delta : float
    separation between the two particles

seed : integer
    set the seed if desired

*args, **kwargs : see create_state


def create_state(image, pos, rad, slab=None, sigma=<NUM_LIT>, conf=conf_simple):

<EOL>if not hasattr(rad, '<STR_LIT>'):<EOL><INDENT>rad = rad*np.ones(pos.shape[<NUM_LIT:0>])<EOL><DEDENT>model = models.models[conf.get('<STR_LIT>')]()<EOL>components = []<EOL>for k,v in iteritems(conf.get('<STR_LIT>', {})):<EOL><INDENT>args = conf.get('<STR_LIT:args>').get(k, {})<EOL>comp = model.registry[k][v](**args)<EOL>components.append(comp)<EOL><DEDENT>sphs = objs.PlatonicSpheresCollection(pos, rad)<EOL>if slab is not None:<EOL><INDENT>sphs = ComponentCollection([sphs, objs.Slab(zpos=slab+pad)], category='<STR_LIT>')<EOL><DEDENT>components.append(sphs)<EOL>s = states.ImageState(image, components, sigma=sigma)<EOL>if isinstance(image, util.NullImage):<EOL><INDENT>s.model_to_data()<EOL><DEDENT>return s<EOL>

Create a state from a blank image, set of pos and radii

Parameters:
-----------
image : `peri.util.Image` object
    raw confocal image with which to compare.

pos : initial conditions for positions (in raw image coordinates)
rad : initial conditions for radii array (can be scalar)
sigma : float, noise level

slab : float
    z-position of the microscope slide in the image (pixel units)


p, r = [], []<EOL>for i in itertools.count():<EOL><INDENT>try:<EOL><INDENT>p.append([d['<STR_LIT>'.format(i, c)] for c in '<STR_LIT>'])<EOL>r.append(d['<STR_LIT>'.format(i)])<EOL><DEDENT>except KeyError:<EOL><INDENT>break<EOL><DEDENT><DEDENT>return np.array(p), np.array(r)<EOL>

Given a dictionary of a states params:values, returns the pos & rad.


od = OrderedDict()<EOL>for p in st.params:<EOL><INDENT>od.update({p:st.state[p]})<EOL><DEDENT>if include_iminfo:<EOL><INDENT>od.update({ '<STR_LIT>':st.image.filename,<EOL>'<STR_LIT>':str(st.image.tile)})<EOL><DEDENT>return od<EOL>

Represents a state as an OrderedDict

    Parameters
    ----------
        st : :class:``peri.states.State``
            The state to represent.
        include_iminfo : Bool, optional
            If set, includes two additional keys, ``'image.filename'`` and
            ``'image.tile'`` with corresponding info about the image.
            Default is True.

    Returns
    -------
        ``collections.OrderedDict``


ind0, ind1 = [], []<EOL>for i in range(len(p0)):<EOL><INDENT>dist = np.sqrt(((p0[i] - p1)**<NUM_LIT:2>).sum(axis=-<NUM_LIT:1>))<EOL>if cutoff is None:<EOL><INDENT>ind1.append(dist.argmin())<EOL><DEDENT>elif dist.min() < cutoff:<EOL><INDENT>ind0.append(i)<EOL>ind1.append(dist.argmin())<EOL><DEDENT><DEDENT>if cutoff is None:<EOL><INDENT>return ind1<EOL><DEDENT>return ind0, ind1<EOL>

Correlate closest particles with each other (within cutoff).

Returns ind0, ind1 so that p0[ind0] is close to p1[ind1].

Parameters
----------
    p0, p1 : numpy.ndarray
        The particle positions.
    cutoff : Float or None, optional
        If not None, only returns particle indices with distance less
        than `cutoff`. Default is None.

Returns
-------
    ind0, ind1 : List
        The lists of particle indices, p0[ind0] is close to p1[ind1].


def sorted_files(globber, num_sort=True, num_indices=None, return_num=False):

files = glob.glob(globber)<EOL>files.sort()<EOL>if not num_sort:<EOL><INDENT>return files<EOL><DEDENT>num_indices = num_indices or np.s_[:]<EOL>allfiles = []<EOL>for fn in files:<EOL><INDENT>nums = re.findall(r'<STR_LIT>', fn)<EOL>data = [int(n) for n in nums[num_indices]] + [fn]<EOL>allfiles.append(data)<EOL><DEDENT>allfiles = sorted(allfiles)<EOL>if return_num:<EOL><INDENT>return allfiles<EOL><DEDENT>return [f[-<NUM_LIT:1>] for f in allfiles]<EOL>

Give a globbing expression of files to find. They will be sorted upon return.
This function is most useful when sorting does not provide numerical order,
e.g.:
    9 -> 12 returned as 10 11 12 9 by string sort

In this case use num_sort=True, and it will be sorted by numbers whose index
is given by num_indices (possibly None for all numbers) then by string.


return state.get('<STR_LIT>').get()[state.inner].mean()<EOL>

Calculates the packing fraction of a state.

Parameters
----------
    state : :class:`peri.states.ImageState`

Returns
-------
    Float
        The volume fraction


def good_particles(state, inbox=True, inboxrad=False, fullinbox=False,<EOL>pos=None, rad=None, ishape=None):

if pos is None:<EOL><INDENT>pos = state.obj_get_positions()<EOL><DEDENT>if rad is None:<EOL><INDENT>rad = state.obj_get_radii()<EOL><DEDENT>mask = rad > <NUM_LIT:0><EOL>if (inbox | inboxrad | fullinbox):<EOL><INDENT>if fullinbox:<EOL><INDENT>mask &= trim_box(state, pos, rad=-rad, ishape=ishape)<EOL><DEDENT>elif inboxrad:<EOL><INDENT>mask &= trim_box(state, pos, rad=rad, ishape=ishape)<EOL><DEDENT>else:<EOL><INDENT>mask &= trim_box(state, pos, rad=None, ishape=ishape)<EOL><DEDENT><DEDENT>return mask<EOL>

Returns a mask of `good' particles as defined by
    * radius > 0
    * position inside box

Parameters
----------
    state : :class:`peri.states.ImageState`
        The state to identify the good particles. If pos, rad, and ishape
        are provided, then this does not need to be passed.
    inbox : Bool
        Whether to only count particle centers within the image. Default
        is True.
    inboxrad : Bool
        Whether to only count particles that overlap the image at all.
        Default is False.
    fullinbox : Bool
        Whether to only include particles which are entirely in the
        image. Default is False
    pos : [3,N] np.ndarray or None
        If not None, the particles' positions.
    rad : [N] element numpy.ndarray or None
        If not None, the particles' radii.
    ishape : 3-element list-like or None
        If not None, the inner region of the state.

Returns
-------
    mask : np.ndarray of bools
        A boolean mask of which particles are good (True) or bad.
See Also
--------
    trim_box


def _eval_firstorder(self, rvecs, data, sigma):

if not self.blocksize:<EOL><INDENT>dist_between_points = self._distance_matrix(rvecs, self.x)<EOL>gaussian_weights = self._weight(dist_between_points, sigma=sigma)<EOL>return gaussian_weights.dot(data) / gaussian_weights.sum(axis=<NUM_LIT:1>)<EOL><DEDENT>else:<EOL><INDENT>ans = np.zeros(rvecs.shape[<NUM_LIT:0>], dtype='<STR_LIT:float>')<EOL>bs = self.blocksize<EOL>for a in range(<NUM_LIT:0>, rvecs.shape[<NUM_LIT:0>], bs):<EOL><INDENT>dist = self._distance_matrix(rvecs[a:a+bs], self.x)<EOL>weights = self._weight(dist, sigma=sigma)<EOL>ans[a:a+bs] += weights.dot(data) / weights.sum(axis=<NUM_LIT:1>)<EOL><DEDENT>return ans<EOL><DEDENT>


return (a[:, None] - b[None, :])**<NUM_LIT:2><EOL>

Pairwise distance between each point in `a` and each point in `b`


sigma = sigma or self.filter_size<EOL>if not self.clip:<EOL><INDENT>o = np.exp(-rsq / (<NUM_LIT:2>*sigma**<NUM_LIT:2>))<EOL><DEDENT>else:<EOL><INDENT>o = np.zeros(rsq.shape, dtype='<STR_LIT:float>')<EOL>m = (rsq < self.clipsize**<NUM_LIT:2>)<EOL>o[m] = np.exp(-rsq[m] / (<NUM_LIT:2>*sigma**<NUM_LIT:2>))<EOL><DEDENT>return o<EOL>


g = self.filter_size<EOL>dist0 = self._distance_matrix(self.x, self.x)<EOL>dist1 = self._distance_matrix(rvecs, self.x)<EOL>tmp = self._weight(dist0, g).dot(self.d)<EOL>out = self._weight(dist1, g).dot(self.d)<EOL>for i in range(self.iterations):<EOL><INDENT>out = out + self._weight(dist1, g).dot(self.d - tmp)<EOL>tmp = tmp + self._weight(dist0, g).dot(self.d - tmp)<EOL>g *= self.damp<EOL><DEDENT>return out<EOL>


def sq(x): return (x * x)<EOL>matrix = sq(a[:, <NUM_LIT:0>][:, None] - b[:, <NUM_LIT:0>][None, :])<EOL>for x, y in zip(a.T[<NUM_LIT:1>:], b.T[<NUM_LIT:1>:]):<EOL><INDENT>matrix += sq(x[:, None] - y[None, :])<EOL><DEDENT>return matrix<EOL>


return <NUM_LIT:0.5> * (self.window[<NUM_LIT:0>] + self.window[<NUM_LIT:1>] +<EOL>c * (self.window[<NUM_LIT:1>] - self.window[<NUM_LIT:0>]))<EOL>

Convert cheb coordinates to windowdow coordinates


return self.modelstr['<STR_LIT>']<EOL>


error = False<EOL>regex = re.compile('<STR_LIT>')<EOL>if '<STR_LIT>' not in self.modelstr:<EOL><INDENT>raise ModelError(<EOL>'<STR_LIT>'<EOL>'<STR_LIT>'<EOL>)<EOL><DEDENT>for name, eq in iteritems(self.modelstr):<EOL><INDENT>var = regex.findall(eq)<EOL>for v in var:<EOL><INDENT>v = re.sub(r"<STR_LIT>", '<STR_LIT>', v)<EOL>if v not in self.varmap:<EOL><INDENT>log.error(<EOL>"<STR_LIT>" %<EOL>(v, name, eq, self.varmap)<EOL>)<EOL>error = True<EOL><DEDENT><DEDENT><DEDENT>if error:<EOL><INDENT>raise ModelError('<STR_LIT>')<EOL><DEDENT>

Make sure that the required comps are included in the list of
components supplied by the user. Also check that the parameters are
consistent across the many components.


error = False<EOL>compcats = [c.category for c in comps]<EOL>for k, v in iteritems(self.varmap):<EOL><INDENT>if k not in self.modelstr['<STR_LIT>']:<EOL><INDENT>log.warn('<STR_LIT>' % (k,v))<EOL><DEDENT>if v not in compcats:<EOL><INDENT>log.error('<STR_LIT>' % (k,v))<EOL>error = True<EOL><DEDENT><DEDENT>if error:<EOL><INDENT>raise ModelError('<STR_LIT>')<EOL><DEDENT>

Check that the list of components `comp` is compatible with both the
varmap and modelstr for this Model


return '<STR_LIT:d>'+name<EOL>

Transform a variable name into a derivative


def do_internal_run(self, initial_count=<NUM_LIT:0>, subblock=None, update_derr=True):

self._inner_run_counter = initial_count; good_step = True<EOL>n_good_steps = <NUM_LIT:0><EOL>CLOG.debug('<STR_LIT>')<EOL>_last_residuals = self.calc_residuals().copy()<EOL>while ((self._inner_run_counter < self.run_length) & good_step &<EOL>(not self.check_terminate())):<EOL><INDENT>if self.check_Broyden_J() and self._inner_run_counter != <NUM_LIT:0>:<EOL><INDENT>self.update_Broyden_J()<EOL><DEDENT>if self.check_update_eig_J() and self._inner_run_counter != <NUM_LIT:0>:<EOL><INDENT>self.update_eig_J()<EOL><DEDENT>er0 = <NUM_LIT:1>*self.error<EOL>delta_vals = self.find_LM_updates(self.calc_grad(),<EOL>do_correct_damping=False, subblock=subblock)<EOL>er1 = self.update_function(self.param_vals + delta_vals)<EOL>good_step = er1 < er0<EOL>if good_step:<EOL><INDENT>n_good_steps += <NUM_LIT:1><EOL>CLOG.debug('<STR_LIT>' % (er0, er1))<EOL>self.update_param_vals(delta_vals, incremental=True)<EOL>self._last_residuals = _last_residuals.copy()<EOL>if update_derr:<EOL><INDENT>self._last_error = er0<EOL><DEDENT>self.error = er1<EOL>_last_residuals = self.calc_residuals().copy()<EOL><DEDENT>else:<EOL><INDENT>er0_0 = self.update_function(self.param_vals)<EOL>CLOG.debug('<STR_LIT>')<EOL>if np.abs(er0 - er0_0) > <NUM_LIT>:<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT><DEDENT>self._inner_run_counter += <NUM_LIT:1><EOL><DEDENT>return n_good_steps<EOL>

Takes more steps without calculating J again.

Given a fixed damping, J, JTJ, iterates calculating steps, with
optional Broyden or eigendirection updates. Iterates either until
a bad step is taken or for self.run_length times.
Called internally by do_run_2() but is also useful on its own.

Parameters
----------
    initial_count : Int, optional
        The initial count of the run. Default is 0. Increasing from
        0 effectively temporarily decreases run_length.
    subblock : None or np.ndarray of bools, optional
        If not None, a boolean mask which determines which sub-
        block of parameters to run over. Default is None, i.e.
        all the parameters.
    update_derr : Bool, optional
        Set to False to not update the variable that determines
        delta_err, preventing premature termination through errtol.

Notes
-----
It might be good to do something similar to update_derr with the
parameter values, but this is trickier because of Broyden updates
and _fresh_J.


if not self._has_run:<EOL><INDENT>return False<EOL><DEDENT>else:<EOL><INDENT>terminate = self.check_completion()<EOL>terminate |= (self._num_iter >= self.max_iter)<EOL>return terminate<EOL><DEDENT>

Returns a Bool of whether to terminate.

Checks whether a satisfactory minimum has been found or whether
too many iterations have occurred.


bools = tile.contains(positions)<EOL>return np.arange(bools.size)[bools]<EOL>

Finds the particles in a tile, as numpy.ndarray of ints.

Parameters
----------
    positions : `numpy.ndarray`
        [N,3] array of the particle positions to check in the tile
    tile : :class:`peri.util.Tile` instance
        Tile of the region inside which to check for particles.

Returns
-------
    numpy.ndarray, int
        The indices of the particles in the tile.


del self.J<EOL>self.J = np.zeros([self.param_vals.size, self.data.size])<EOL>dp = np.zeros_like(self.param_vals)<EOL>f0 = self.model.copy()<EOL>for a in range(self.param_vals.size):<EOL><INDENT>dp *= <NUM_LIT:0><EOL>dp[a] = self.dl[a]<EOL>f1 = self.func(self.param_vals + dp, *self.func_args, **self.func_kwargs)<EOL>grad_func = (f1 - f0) / dp[a]<EOL>self.J[a] = -grad_func<EOL><DEDENT>


raise NotImplementedError('<STR_LIT>')<EOL>


def separate_particles_into_groups(s, region_size=<NUM_LIT>, bounds=None,<EOL>doshift=False):

imtile = s.oshape.translate(-s.pad)<EOL>bounding_tile = (imtile if bounds is None else Tile(bounds[<NUM_LIT:0>], bounds[<NUM_LIT:1>]))<EOL>rs = (np.ones(bounding_tile.dim, dtype='<STR_LIT:int>')*region_size if<EOL>np.size(region_size) == <NUM_LIT:1> else np.array(region_size))<EOL>n_translate = np.ceil(bounding_tile.shape.astype('<STR_LIT:float>')/rs).astype('<STR_LIT:int>')<EOL>particle_groups = []<EOL>tile = Tile(left=bounding_tile.l, right=bounding_tile.l + rs)<EOL>if doshift == '<STR_LIT>':<EOL><INDENT>doshift = np.random.choice([True, False])<EOL><DEDENT>if doshift:<EOL><INDENT>shift = rs // <NUM_LIT:2><EOL>n_translate += <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>shift = <NUM_LIT:0><EOL><DEDENT>deltas = np.meshgrid(*[np.arange(i) for i in n_translate])<EOL>positions = s.obj_get_positions()<EOL>if bounds is None:<EOL><INDENT>positions = np.clip(positions, imtile.l+<NUM_LIT>, imtile.r-<NUM_LIT>)<EOL><DEDENT>groups = list(map(lambda *args: find_particles_in_tile(positions,<EOL>tile.translate( np.array(args) * rs - shift)), *[d.ravel()<EOL>for d in deltas]))<EOL>for i in range(len(groups)-<NUM_LIT:1>, -<NUM_LIT:1>, -<NUM_LIT:1>):<EOL><INDENT>if groups[i].size == <NUM_LIT:0>:<EOL><INDENT>groups.pop(i)<EOL><DEDENT><DEDENT>assert _check_groups(s, groups)<EOL>return groups<EOL>

Separates particles into convenient groups for optimization.

Given a state, returns a list of groups of particles. Each group of
particles are located near each other in the image. Every particle
located in the desired region is contained in exactly 1 group.

Parameters
----------
s : :class:`peri.states.ImageState`
    The peri state to find particles in.
region_size : Int or 3-element list-like of ints, optional
    The size of the box. Groups particles into boxes of shape
    (region_size[0], region_size[1], region_size[2]). If region_size
    is a scalar, the box is a cube of length region_size.
    Default is 40.
bounds : 2-element list-like of 3-element lists, optional
    The sub-region of the image over which to look for particles.
        bounds[0]: The lower-left  corner of the image region.
        bounds[1]: The upper-right corner of the image region.
    Default (None -> ([0,0,0], s.oshape.shape)) is a box of the entire
    image size, i.e. the default places every particle in the image
    somewhere in the groups.
doshift : {True, False, `'rand'`}, optional
    Whether or not to shift the tile boxes by half a region size, to
    prevent the same particles to be chosen every time. If `'rand'`,
    randomly chooses either True or False. Default is False

Returns
-------
particle_groups : List
    Each element of particle_groups is an int numpy.ndarray of the
    group of nearby particles. Only contains groups with a nonzero
    number of particles, so the elements don't necessarily correspond
    to a given image region.


def reset(self, new_region_size=None, do_calc_size=True, new_damping=None,<EOL>new_max_mem=None):

if new_region_size is not None:<EOL><INDENT>self.region_size = new_region_size<EOL><DEDENT>if new_max_mem != None:<EOL><INDENT>self.max_mem = new_max_mem<EOL><DEDENT>if do_calc_size:<EOL><INDENT>self.region_size = calc_particle_group_region_size(self.state,<EOL>region_size=self.region_size, max_mem=self.max_mem)<EOL><DEDENT>self.stats = []<EOL>self.particle_groups = separate_particles_into_groups(self.state,<EOL>self.region_size, doshift='<STR_LIT>')<EOL>if new_damping is not None:<EOL><INDENT>self._kwargs.update({'<STR_LIT>':new_damping})<EOL><DEDENT>if self.save_J:<EOL><INDENT>if len(self.particle_groups) > <NUM_LIT>:<EOL><INDENT>CLOG.warn('<STR_LIT>')<EOL><DEDENT>self._tempfiles = []<EOL>self._has_saved_J = []<EOL>for a in range(len(self.particle_groups)):<EOL><INDENT>for _ in ['<STR_LIT>','<STR_LIT>']:<EOL><INDENT>self._tempfiles.append(tempfile.TemporaryFile(dir=os.getcwd()))<EOL><DEDENT>self._has_saved_J.append(False)<EOL><DEDENT><DEDENT>

Resets the particle groups and optionally the region size and damping.

Parameters
----------
    new_region_size : : Int or 3-element list-like of ints, optional
        The region size for sub-blocking particles. Default is 40
    do_calc_size : Bool, optional
        If True, calculates the region size internally based on
        the maximum allowed memory. Default is True
    new_damping : Float or None, optional
        The new damping of the optimizer. Set to None to leave
        as the default for LMParticles. Default is None.
    new_max_mem : Numeric, optional
        The maximum allowed memory for J to occupy. Default is 1e9


CLOG.debug('<STR_LIT>')<EOL>delta_vals = self.param_vals - self._last_vals<EOL>delta_residuals = self.calc_residuals() - self._last_residuals<EOL>nrm = np.sqrt(np.dot(delta_vals, delta_vals))<EOL>direction = delta_vals / nrm<EOL>vals = delta_residuals / nrm<EOL>self._rank_1_J_update(direction, vals)<EOL>self.JTJ = np.dot(self.J, self.J.T)<EOL>


def update_param_vals(self, new_vals, incremental=False):

self._last_vals = self.param_vals.copy()<EOL>if incremental:<EOL><INDENT>self.param_vals += new_vals<EOL><DEDENT>else:<EOL><INDENT>self.param_vals = new_vals.copy()<EOL><DEDENT>self._fresh_JTJ = False<EOL>

Updates the current set of parameter values and previous values,
sets a flag to re-calculate J.

Parameters
----------
    new_vals : numpy.ndarray
        The new values to update to
    incremental : Bool, optional
        Set to True to make it an incremental update relative
        to the old parameters. Default is False


self.calc_J()<EOL>step = np.ceil(<NUM_LIT> * self.J.shape[<NUM_LIT:1>]).astype('<STR_LIT:int>')  <EOL>self.JTJ = low_mem_sq(self.J, step=step)<EOL>self._fresh_JTJ = True<EOL>self._J_update_counter = <NUM_LIT:0><EOL>if np.any(np.isnan(self.JTJ)):<EOL><INDENT>raise FloatingPointError('<STR_LIT>')<EOL><DEDENT>self._exp_err = self.error - self.find_expected_error(delta_params='<STR_LIT>')<EOL>


self.model = self.func(param_vals, *self.func_args, **self.func_kwargs)<EOL>d = self.calc_residuals()<EOL>return np.dot(d.flat, d.flat)<EOL>

Takes an array param_vals, updates function, returns the new error


def calc_accel_correction(self, damped_JTJ, delta0):

<EOL>_ = self.update_function(self.param_vals)<EOL>rm0 = self.calc_residuals().copy()<EOL>_ = self.update_function(self.param_vals + delta0)<EOL>rm1 = self.calc_residuals().copy()<EOL>_ = self.update_function(self.param_vals - delta0)<EOL>rm2 = self.calc_residuals().copy()<EOL>der2 = (rm2 + rm1 - <NUM_LIT:2>*rm0)<EOL>corr, res, rank, s = np.linalg.lstsq(damped_JTJ, np.dot(self.J, der2),<EOL>rcond=self.min_eigval)<EOL>corr *= -<NUM_LIT:0.5><EOL>return corr<EOL>

Geodesic acceleration correction to the LM step.

Parameters
----------
    damped_JTJ : numpy.ndarray
        The damped JTJ used to calculate the initial step.
    delta0 : numpy.ndarray
        The initial LM step.

Returns
-------
    corr : numpy.ndarray
        The correction to the original LM step.


terminate = False<EOL>term_dict = self.get_termination_stats(get_cos=self.costol is not None)<EOL>terminate |= np.all(np.abs(term_dict['<STR_LIT>']) < self.paramtol)<EOL>terminate |= (term_dict['<STR_LIT>'] < self.errtol)<EOL>terminate |= (term_dict['<STR_LIT>'] < self.exptol)<EOL>terminate |= (term_dict['<STR_LIT>'] < self.fractol)<EOL>if self.costol is not None:<EOL><INDENT>terminate |= (curcos < term_dict['<STR_LIT>'])<EOL><DEDENT>return terminate<EOL>

Returns a Bool of whether the algorithm has found a satisfactory minimum


if np.all(np.isnan(err_vals)):<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>return np.nanargmin(err_vals)<EOL>

Returns the index of the lowest of the passed values. Catches nans etc.


def calc_model_cosine(self, decimate=None, mode='<STR_LIT>'):

if mode == '<STR_LIT>':<EOL><INDENT>slicer = slice(<NUM_LIT:0>, None, decimate)<EOL>u, sig, v = np.linalg.svd(self.J[:,slicer], full_matrices=False) <EOL>r = self.calc_residuals()[slicer]<EOL>abs_r = np.sqrt((r*r).sum())<EOL>v_r = np.dot(v,r/abs_r)<EOL>projected = np.dot(v.T, v_r)<EOL>abs_cos = np.sqrt((projected*projected).sum())<EOL><DEDENT>elif mode == '<STR_LIT>':<EOL><INDENT>expected_error = self.find_expected_error(delta_params='<STR_LIT>')<EOL>model_sine_2 = expected_error / self.error  <EOL>abs_cos = np.sqrt(<NUM_LIT:1> - model_sine_2)<EOL><DEDENT>else:<EOL><INDENT>raise ValueError('<STR_LIT>')<EOL><DEDENT>return abs_cos<EOL>

Calculates the cosine of the residuals with the model.

Parameters
----------
    decimate : Int or None, optional
        Decimate the residuals by `decimate` pixels. If None, no
        decimation is used. Valid only with mode='svd'. Default
        is None
    mode : {'svd', 'err'}
        Which mode to use; see Notes section. Default is 'err'.

Returns
-------
    abs_cos : numpy.float64
        The absolute value of the model cosine.

Notes
-----
The model cosine is defined in terms of the geometric view of
curve-fitting, as a model manifold embedded in a high-dimensional
space. The model cosine is the cosine of the residuals vector
with its projection on the tangent space: :math:`cos(phi) = |P^T r|/|r|`
where :math:`P^T` is the projection operator onto the model manifold
and :math:`r` the residuals. This can be calculated two ways: By
calculating the projection operator P directly with SVD (mode=`svd`),
or by using the expected error if the model were linear to calculate
a model sine first (mode=`err`). Since the SVD of a large matrix is
slow, mode=`err` is faster.

`decimate` allows for every nth pixel only to be counted in the
SVD matrix of J for speed. While this is n x faster, it is
considerably less accurate, so the default is no decimation.


self.opt_obj.update_function(param_vals)<EOL>return self.opt_obj.get_error()<EOL>


while not self.check_terminate():<EOL><INDENT>self._has_run = True<EOL>self._run2()<EOL>self._num_iter += <NUM_LIT:1><EOL><DEDENT>

LM run evaluating 2 steps (damped and not) and choosing the best.

After finding the best of 2 steps, runs with that damping + Broyden
or eigendirection updates, until deciding to do a full-J update.
Only changes damping after full-J updates.


residuals = self.calc_residuals()<EOL>return <NUM_LIT:2>*np.dot(self.J, residuals)<EOL>

The gradient of the cost w.r.t. the parameters.


def do_levmarq_particles(s, particles, damping=<NUM_LIT:1.0>, decrease_damp_factor=<NUM_LIT>,<EOL>run_length=<NUM_LIT:4>, collect_stats=False, max_iter=<NUM_LIT:2>, **kwargs):

lp = LMParticles(s, particles, damping=damping, run_length=run_length,<EOL>decrease_damp_factor=decrease_damp_factor, max_iter=max_iter,<EOL>**kwargs)<EOL>lp.do_run_2()<EOL>if collect_stats:<EOL><INDENT>return lp.get_termination_stats()<EOL><DEDENT>

Levenberg-Marquardt optimization on a set of particles.

Convenience wrapper for LMParticles. Same keyword args, but the
defaults have been set to useful values for optimizing particles.
See LMParticles and LMEngine for documentation.

See Also
--------
    do_levmarq_all_particle_groups : Levenberg-Marquardt optimization
        of all the particles in the state.

    do_levmarq : Levenberg-Marquardt optimization of the entire state;
        useful for optimizing global parameters.

    LMParticles : Optimizer object; the workhorse of do_levmarq_particles.

    LMEngine : Engine superclass for all the optimizers.


def calc_particle_group_region_size(s, region_size=<NUM_LIT>, max_mem=<NUM_LIT>, **kwargs):

region_size = np.array(region_size).astype('<STR_LIT:int>')<EOL>def calc_mem_usage(region_size):<EOL><INDENT>rs = np.array(region_size)<EOL>particle_groups = separate_particles_into_groups(s, region_size=<EOL>rs.tolist(), **kwargs)<EOL>numpart = [np.size(g) for g in particle_groups]<EOL>biggroups = [particle_groups[i] for i in np.argsort(numpart)[-<NUM_LIT:5>:]]<EOL>def get_tile_jsize(group):<EOL><INDENT>nms = s.param_particle(group)<EOL>tile = s.get_update_io_tiles(nms, s.get_values(nms))[<NUM_LIT:2>]<EOL>return tile.shape.prod() * len(nms)<EOL><DEDENT>mems = [<NUM_LIT:8>*get_tile_jsize(g) for g in biggroups]  <EOL>return np.max(mems)<EOL><DEDENT>im_shape = s.oshape.shape<EOL>if calc_mem_usage(region_size) > max_mem:<EOL><INDENT>while ((calc_mem_usage(region_size) > max_mem) and<EOL>np.any(region_size > <NUM_LIT:2>)):<EOL><INDENT>region_size = np.clip(region_size-<NUM_LIT:1>, <NUM_LIT:2>, im_shape)<EOL><DEDENT><DEDENT>else:<EOL><INDENT>while ((calc_mem_usage(region_size) < max_mem) and<EOL>np.any(region_size < im_shape)):<EOL><INDENT>region_size = np.clip(region_size+<NUM_LIT:1>, <NUM_LIT:2>, im_shape)<EOL><DEDENT>region_size -= <NUM_LIT:1> <EOL><DEDENT>return region_size<EOL>

Finds the biggest region size for LM particle optimization with a
given memory constraint.

Input Parameters
----------------
    s : :class:`peri.states.ImageState`
        The state with the particles
    region_size : Int or 3-element list-like of ints, optional.
        The initial guess for the region size. Default is 40
    max_mem : Numeric, optional
        The maximum memory for the optimizer to take. Default is 1e9

Other Parameters
----------------
    bounds: 2-element list-like of 3-element lists.
        The sub-region of the image over which to look for particles.
            bounds[0]: The lower-left  corner of the image region.
            bounds[1]: The upper-right corner of the image region.
        Default (None -> ([0,0,0], s.oshape.shape)) is a box of the entire
        image size, i.e. the default places every particle in the image
        somewhere in the groups.
Returns
-------
    region_size : numpy.ndarray of ints of the region size.


return self.state.residuals.ravel().copy()<EOL>

See also
--------
:func:`peri.state.States.residuals`


delta_vals = self._last_vals - self.param_vals<EOL>delta_err = self._last_error - self.error<EOL>frac_err = delta_err / self.error<EOL>to_return = {'<STR_LIT>':delta_vals, '<STR_LIT>':delta_err,<EOL>'<STR_LIT>':<NUM_LIT:1>*self._num_iter, '<STR_LIT>':frac_err,<EOL>'<STR_LIT:error>':self.error, '<STR_LIT>':self._exp_err}<EOL>if get_cos:<EOL><INDENT>model_cosine = self.calc_model_cosine()<EOL>to_return.update({'<STR_LIT>':model_cosine})<EOL><DEDENT>return to_return<EOL>

Returns a dict of termination statistics

Parameters
----------
    get_cos : Bool, optional
        Whether or not to calcualte the cosine of the residuals
        with the tangent plane of the model using the current J.
        The calculation may take some time. Default is True

Returns
-------
    dict
        Has keys
            delta_vals  : The last change in parameter values.
            delta_err   : The last change in the error.
            exp_err     : The expected (last) change in the error.
            frac_err    : The fractional change in the error.
            num_iter    : The number of iterations completed.
            error       : The current error.


self.update_function(self.param_vals)<EOL>params = np.array(self.param_names)[blk].tolist()<EOL>blk_J = -self.state.gradmodel(params=params, inds=self._inds, flat=False)<EOL>self.J[blk] = blk_J<EOL>self.JTJ = np.dot(self.J, self.J.T)<EOL>if np.any(np.isnan(self.J)) or np.any(np.isnan(self.JTJ)):<EOL><INDENT>raise FloatingPointError('<STR_LIT>')<EOL><DEDENT>

Updates J only for certain parameters, described by the boolean
mask blk.


ans = []<EOL>for g in groups:<EOL><INDENT>ans.extend(g)<EOL><DEDENT>if np.unique(ans).size != np.size(ans):<EOL><INDENT>return False<EOL><DEDENT>elif np.unique(ans).size != s.obj_get_positions().shape[<NUM_LIT:0>]:<EOL><INDENT>return False<EOL><DEDENT>else:<EOL><INDENT>return (np.arange(s.obj_get_radii().size) == np.sort(ans)).all()<EOL><DEDENT>

Ensures that all particles are included in exactly 1 group


self.aug_state.reset()<EOL>super(LMAugmentedState, self).reset(**kwargs)<EOL>


Calls LMParticles.do_run_2 for each group of particles.


if self.check_update_J():<EOL><INDENT>self.update_J()<EOL><DEDENT>else:<EOL><INDENT>if self.check_Broyden_J():<EOL><INDENT>self.update_Broyden_J()<EOL><DEDENT>if self.check_update_eig_J():<EOL><INDENT>self.update_eig_J()<EOL><DEDENT><DEDENT>delta_vals = self.find_LM_updates(self.calc_grad())<EOL>er1 = self.update_function(self.param_vals + delta_vals)<EOL>good_step = (find_best_step([self.error, er1]) == <NUM_LIT:1>)<EOL>if not good_step:<EOL><INDENT>er0 = self.update_function(self.param_vals)<EOL>if np.abs(er0 -self.error)/er0 > <NUM_LIT>:<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT>CLOG.debug('<STR_LIT>')<EOL>CLOG.debug('<STR_LIT>' % (self.error, er1))<EOL>grad = self.calc_grad()<EOL>for _try in range(self._max_inner_loop):<EOL><INDENT>self.increase_damping()<EOL>delta_vals = self.find_LM_updates(grad)<EOL>er1 = self.update_function(self.param_vals + delta_vals)<EOL>good_step = (find_best_step([self.error, er1]) == <NUM_LIT:1>)<EOL>if good_step:<EOL><INDENT>break<EOL><DEDENT><DEDENT>else:<EOL><INDENT>er0 = self.update_function(self.param_vals)<EOL>CLOG.warn('<STR_LIT>')<EOL>if np.abs(er0 -self.error)/er0 > <NUM_LIT>:<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT><DEDENT><DEDENT>if good_step:<EOL><INDENT>self._last_error = self.error<EOL>self.error = er1<EOL>CLOG.debug('<STR_LIT>' % (self._last_error, self.error))<EOL>self.update_param_vals(delta_vals, incremental=True)<EOL>self.decrease_damping()<EOL><DEDENT>


dp = np.zeros(self.p0.size)<EOL>for a in range(param_vals.size):<EOL><INDENT>dp += param_vals[a] * self.directions[a]<EOL><DEDENT>self.state.update(self.state.params, self.p0 + dp)<EOL>self.param_vals[:] = param_vals<EOL>return None<EOL>

Updates with param_vals[i] = distance from self.p0 along self.direction[i].


if not self.save_J:<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT>if not np.all(self._has_saved_J):<EOL><INDENT>raise RuntimeError('<STR_LIT>')<EOL><DEDENT>self._do_run(mode='<STR_LIT>')<EOL>

Calls LMParticles.do_internal_run for each group of particles.


self._J_update_counter += <NUM_LIT:1><EOL>update = self._J_update_counter >= self.update_J_frequency<EOL>return update & (not self._fresh_JTJ)<EOL>

Checks if the full J should be updated.

Right now, just updates after update_J_frequency loops


inds = list(range(self.state.obj_get_positions().shape[<NUM_LIT:0>]))<EOL>self._rad_nms = self.state.param_particle_rad(inds)<EOL>self._pos_nms = self.state.param_particle_pos(inds)<EOL>self._initial_rad = np.copy(self.state.state[self._rad_nms])<EOL>self._initial_pos = np.copy(self.state.state[self._pos_nms]).reshape((-<NUM_LIT:1>,<NUM_LIT:3>))<EOL>self.param_vals[self.rscale_mask] = <NUM_LIT:0><EOL>

Resets the initial radii used for updating the particles. Call
if any of the particle radii or positions have been changed
external to the augmented state.


CLOG.debug('<STR_LIT>')<EOL>vls, vcs = np.linalg.eigh(self.JTJ)<EOL>res0 = self.calc_residuals()<EOL>for a in range(min([self.num_eig_dirs, vls.size])):<EOL><INDENT>stif_dir = vcs[-(a+<NUM_LIT:1>)] <EOL>dl = self.eig_dl <EOL>_ = self.update_function(self.param_vals + dl*stif_dir)<EOL>res1 = self.calc_residuals()<EOL>grad_stif = (res1-res0)/dl<EOL>self._rank_1_J_update(stif_dir, grad_stif)<EOL><DEDENT>self.JTJ = np.dot(self.J, self.J.T)<EOL>_ = self.update_function(self.param_vals)<EOL>


def get_rand_Japprox(s, params, num_inds=<NUM_LIT:1000>, include_cost=False, **kwargs):

start_time = time.time()<EOL>tot_pix = s.residuals.size<EOL>if num_inds < tot_pix:<EOL><INDENT>inds = np.random.choice(tot_pix, size=num_inds, replace=False)<EOL>slicer = None<EOL>return_inds = np.sort(inds)<EOL><DEDENT>else:<EOL><INDENT>inds = None<EOL>return_inds = slice(<NUM_LIT:0>, None)<EOL>slicer = [slice(<NUM_LIT:0>, None)]*len(s.residuals.shape)<EOL><DEDENT>if include_cost:<EOL><INDENT>Jact, ge = s.gradmodel_e(params=params, inds=inds, slicer=slicer,flat=False,<EOL>**kwargs)<EOL>Jact *= -<NUM_LIT:1><EOL>J = [Jact, ge]<EOL><DEDENT>else:<EOL><INDENT>J = -s.gradmodel(params=params, inds=inds, slicer=slicer, flat=False,<EOL>**kwargs)<EOL><DEDENT>CLOG.debug('<STR_LIT>' % (time.time()-start_time))<EOL>return J, return_inds<EOL>

Calculates a random approximation to J by returning J only at a
set of random pixel/voxel locations.

Parameters
----------
    s : :class:`peri.states.State`
        The state to calculate J for.
    params : List
        The list of parameter names to calculate the gradient of.
    num_inds : Int, optional.
        The number of pix/voxels at which to calculate the random
        approximation to J. Default is 1000.
    include_cost : Bool, optional
        Set to True to append a finite-difference measure of the full
        cost gradient onto the returned J.

Other Parameters
----------------
    All kwargs parameters get passed to s.gradmodel only.

Returns
-------
    J : numpy.ndarray
        [d, num_inds] array of J, at the given indices.

    return_inds : numpy.ndarray or slice
        [num_inds] element array or slice(0, None) of the model
        indices at which J was evaluated.


def fit_comp(new_comp, old_comp, **kwargs):

<EOL>new_cat = new_comp.category<EOL>new_comp.category = '<STR_LIT>'<EOL>fake_s = states.ImageState(Image(old_comp.get().copy()), [new_comp], pad=<NUM_LIT:0>,<EOL>mdl=mdl.SmoothFieldModel())<EOL>do_levmarq(fake_s, new_comp.params, **kwargs)<EOL>new_comp.category = new_cat<EOL>

Fits a new component to an old component

Calls do_levmarq to match the .get() fields of the two objects. The
parameters of new_comp are modified in place.

Parameters
----------
new_comp : :class:`peri.comps.comp`
    The new object, whose parameters to update to fit the field of
    `old_comp`. Must have a .get() attribute which returns an ndarray
old_comp : peri.comp
    The old ilm to match to.

Other Parameters
----------------
    Any keyword arguments to be passed to the optimizer LMGlobals
    through do_levmarq.

See Also
--------
do_levmarq : Levenberg-Marquardt minimization using a random subset
    of the image pixels.


inner_tile = st.ishape.intersection([st.ishape, padded_tile])<EOL>return inner_tile.translate(-st.pad)<EOL>

Translates a tile in the padded image to the unpadded image.

Given a state and a tile that corresponds to the padded image, returns
a tile that corresponds to the the corresponding pixels of the difference
image

Parameters
----------
    st : :class:`peri.states.State`
        The state
    padded_tile : :class:`peri.util.Tile`
        The tile in the padded image.

Returns
-------
    :class:`peri.util.Tile`
        The tile corresponding to padded_tile in the unpadded image.


def remove_bad_particles(st, min_rad='<STR_LIT>', max_rad='<STR_LIT>', min_edge_dist=<NUM_LIT>,<EOL>check_rad_cutoff=[<NUM_LIT>, <NUM_LIT:15>], check_outside_im=True,<EOL>tries=<NUM_LIT:50>, im_change_frac=<NUM_LIT>, **kwargs):

is_near_im_edge = lambda pos, pad: (((pos + st.pad) < pad) | (pos ><EOL>np.array(st.ishape.shape) + st.pad - pad)).any(axis=<NUM_LIT:1>)<EOL>removed = <NUM_LIT:0><EOL>attempts = <NUM_LIT:0><EOL>n_tot_part = st.obj_get_positions().shape[<NUM_LIT:0>]<EOL>q10 = int(<NUM_LIT:0.1> * n_tot_part)  <EOL>r_sig = np.sort(st.obj_get_radii())[q10:-q10].std()<EOL>r_med = np.median(st.obj_get_radii())<EOL>if max_rad == '<STR_LIT>':<EOL><INDENT>max_rad = r_med + <NUM_LIT:15>*r_sig<EOL><DEDENT>if min_rad == '<STR_LIT>':<EOL><INDENT>min_rad = r_med - <NUM_LIT>*r_sig<EOL><DEDENT>if check_rad_cutoff == '<STR_LIT>':<EOL><INDENT>check_rad_cutoff = [r_med - <NUM_LIT>*r_sig, r_med + <NUM_LIT>*r_sig]<EOL><DEDENT>rad_wrong_size = np.nonzero(<EOL>(st.obj_get_radii() < min_rad) | (st.obj_get_radii() > max_rad))[<NUM_LIT:0>]<EOL>near_im_edge = np.nonzero(is_near_im_edge(st.obj_get_positions(),<EOL>min_edge_dist - st.pad))[<NUM_LIT:0>]<EOL>delete_inds = np.unique(np.append(rad_wrong_size, near_im_edge)).tolist()<EOL>delete_poses = st.obj_get_positions()[delete_inds].tolist()<EOL>message = ('<STR_LIT:->'*<NUM_LIT> + '<STR_LIT>' + '<STR_LIT:->'*<NUM_LIT> +<EOL>'<STR_LIT>')<EOL>with log.noformat():<EOL><INDENT>CLOG.info(message)<EOL><DEDENT>for pos in delete_poses:<EOL><INDENT>ind = st.obj_closest_particle(pos)<EOL>old_err = st.error<EOL>p, r = st.obj_remove_particle(ind)<EOL>p = p[<NUM_LIT:0>]<EOL>r = r[<NUM_LIT:0>]<EOL>part_msg = '<STR_LIT>' % (<EOL>tuple(p) + (r,) + (old_err, st.error))<EOL>with log.noformat():<EOL><INDENT>CLOG.info(part_msg)<EOL><DEDENT>removed += <NUM_LIT:1><EOL><DEDENT>check_rad_inds = np.nonzero((st.obj_get_radii() < check_rad_cutoff[<NUM_LIT:0>]) |<EOL>(st.obj_get_radii() > check_rad_cutoff[<NUM_LIT:1>]))[<NUM_LIT:0>]<EOL>if check_outside_im:<EOL><INDENT>check_edge_inds = np.nonzero(<EOL>is_near_im_edge(st.obj_get_positions(), st.pad))[<NUM_LIT:0>]<EOL>check_inds = np.unique(np.append(check_rad_inds, check_edge_inds))<EOL><DEDENT>else:<EOL><INDENT>check_inds = check_rad_inds<EOL><DEDENT>check_inds = check_inds[np.argsort(st.obj_get_radii()[check_inds])]<EOL>tries = np.min([tries, check_inds.size])<EOL>check_poses = st.obj_get_positions()[check_inds[:tries]].copy()<EOL>for pos in check_poses:<EOL><INDENT>old_err = st.error<EOL>ind = st.obj_closest_particle(pos)<EOL>killed, p, r = check_remove_particle(<EOL>st, ind, im_change_frac=im_change_frac)<EOL>if killed:<EOL><INDENT>removed += <NUM_LIT:1><EOL>check_inds[check_inds > ind] -= <NUM_LIT:1>  <EOL>delete_poses.append(pos)<EOL>part_msg = '<STR_LIT>' % (<EOL>p + r + (old_err, st.error))<EOL>with log.noformat():<EOL><INDENT>CLOG.info(part_msg)<EOL><DEDENT><DEDENT><DEDENT>return removed, delete_poses<EOL>

Removes improperly-featured particles from the state, based on a
combination of particle size and the change in error on removal.

Parameters
-----------
st : :class:`peri.states.State`
    The state to remove bad particles from.
min_rad : Float, optional
    All particles with radius below min_rad are automatically deleted.
    Set to 'calc' to make it the median rad - 25* radius std.
    Default is 'calc'.

max_rad : Float, optional
    All particles with radius above max_rad are automatically deleted.
    Set to 'calc' to make it the median rad + 15* radius std.
    Default is 'calc'.

min_edge_dist : Float, optional
    All particles within min_edge_dist of the (padded) image
    edges are automatically deleted. Default is 2.0

check_rad_cutoff : 2-element list of floats, optional
    Particles with radii < check_rad_cutoff[0] or > check_rad_cutoff[1]
    are checked if they should be deleted. Set to 'calc' to make it the
    median rad +- 3.5 * radius std. Default is [3.5, 15].

check_outside_im : Bool, optional
    If True, checks if particles located outside the unpadded image
    should be deleted. Default is True.

tries : Int, optional
    The maximum number of particles with radii < check_rad_cutoff
    to try to remove. Checks in increasing order of radius size.
    Default is 50.

im_change_frac : Float, , optional
    Number between 0 and 1. If removing a particle decreases the
    error by less than im_change_frac*the change in the image, then
    the particle is deleted. Default is 0.2

Returns
-------
removed: Int
    The cumulative number of particles removed.


def identify_misfeatured_regions(st, filter_size=<NUM_LIT:5>, sigma_cutoff=<NUM_LIT>):

<EOL>r = st.residuals<EOL>weights = np.ones([filter_size]*len(r.shape), dtype='<STR_LIT:float>')<EOL>weights /= weights.sum()<EOL>f = np.sqrt(nd.filters.convolve(r*r, weights, mode='<STR_LIT>'))<EOL>if sigma_cutoff == '<STR_LIT>':<EOL><INDENT>max_ok = initializers.otsu_threshold(f)<EOL><DEDENT>else:<EOL><INDENT>max_ok = f.mean() + sigma_cutoff * f.std()<EOL><DEDENT>bad = f > max_ok<EOL>labels, n = nd.measurements.label(bad)<EOL>inds = []<EOL>for i in range(<NUM_LIT:1>, n+<NUM_LIT:1>):<EOL><INDENT>inds.append(np.nonzero(labels == i))<EOL><DEDENT>tiles = [Tile(np.min(ind, axis=<NUM_LIT:1>), np.max(ind, axis=<NUM_LIT:1>)+<NUM_LIT:1>) for ind in inds]<EOL>volumes = [t.volume for t in tiles]<EOL>return [tiles[i] for i in np.argsort(volumes)[::-<NUM_LIT:1>]]<EOL>

Identifies regions of missing/misfeatured particles based on the
residuals' local deviation from uniform Gaussian noise.

Parameters
----------
st : :class:`peri.states.State`
    The state in which to identify mis-featured regions.

filter_size : Int, best if odd.
    The size of the filter for calculating the local standard deviation;
    should approximately be the size of a poorly featured region in
    each dimension. Default is 5.

sigma_cutoff : Float or `otsu`, optional
    The max allowed deviation of the residuals from what is expected,
    in units of the residuals' standard deviation. Lower means more
    sensitive, higher = less sensitive. Default is 8.0, i.e. one pixel
    out of every 7*10^11 is mis-identified randomly. In practice the
    noise is not Gaussian so there are still some regions mis-identified
    as improperly featured. Set to ```otsu``` to calculate this number
    based on an automatic Otsu threshold.

Returns
-------
tiles : List of :class:`peri.util.Tile`
    Each tile is the smallest bounding tile that contains an improperly
    featured region. The list is sorted by the tile's volume.

Notes
-----
Algorithm is
1.  Create a field of the local standard deviation, as measured over
    a hypercube of size filter_size.
2.  Find the maximum reasonable value of the field. [The field should
    be a random variable with mean of r.std() and standard deviation
    of ~r.std() / sqrt(N), where r is the residuals and N is the
    number of pixels in the hypercube.]
3.  Label & Identify the misfeatured regions as portions where
    the local error is too large.
4.  Parse the misfeatured regions into tiles.
5.  Return the sorted tiles.
The Otsu option to calculate the sigma cutoff works well for images
that actually contain missing particles, returning a number similar
to one calculated with a sigma cutoff. However, if the image is
well-featured with Gaussian residuals, then the Otsu threshold
splits the Gaussian down the middle instead of at the tails, which
is very bad. So use with caution.


def add_missing_particles(st, rad='<STR_LIT>', tries=<NUM_LIT:50>, **kwargs):

if rad == '<STR_LIT>':<EOL><INDENT>rad = guess_add_radii(st)<EOL><DEDENT>guess, npart = feature_guess(st, rad, **kwargs)<EOL>tries = np.min([tries, npart])<EOL>accepts, new_poses = check_add_particles(<EOL>st, guess[:tries], rad=rad, **kwargs)<EOL>return accepts, new_poses<EOL>

Attempts to add missing particles to the state.

Operates by:
(1) featuring the difference image using feature_guess,
(2) attempting to add the featured positions using check_add_particles.

Parameters
----------
st : :class:`peri.states.State`
    The state to check adding particles to.
rad : Float or 'calc', optional
    The radius of the newly-added particles and of the feature size for
    featuring. Default is 'calc', which uses the median of the state's
    current radii.
tries : Int, optional
    How many particles to attempt to add. Only tries to add the first
    ``tries`` particles, in order of mass. Default is 50.

Other Parameters
----------------
invert : Bool, optional
    Whether to invert the image. Default is ``True``, i.e. dark particles
minmass : Float or None, optionals
    The minimum mass/masscut of a particle. Default is ``None``=calcualted
    by ``feature_guess``.
use_tp : Bool, optional
    Whether to use trackpy in feature_guess. Default is False, since
    trackpy cuts out particles at the edge.

do_opt : Bool, optional
    Whether to optimize the particle position before checking if it
    should be kept. Default is True (optimizes position).
im_change_frac : Float, optional
    How good the change in error needs to be relative to the change
    in the difference image. Default is 0.2; i.e. if the error does
    not decrease by 20% of the change in the difference image, do
    not add the particle.

min_derr : Float or '3sig', optional
    The minimal improvement in error to add a particle. Default
    is ``'3sig' = 3*st.sigma``.

Returns
-------
accepts : Int
    The number of added particles
new_poses : [N,3] list
    List of the positions of the added particles. If ``do_opt==True``,
    then these positions will differ from the input 'guess'.


def add_subtract(st, max_iter=<NUM_LIT:7>, max_npart='<STR_LIT>', max_mem=<NUM_LIT>,<EOL>always_check_remove=False, **kwargs):

if max_npart == '<STR_LIT>':<EOL><INDENT>max_npart = <NUM_LIT> * st.obj_get_positions().shape[<NUM_LIT:0>]<EOL><DEDENT>total_changed = <NUM_LIT:0><EOL>_change_since_opt = <NUM_LIT:0><EOL>removed_poses = []<EOL>added_poses0 = []<EOL>added_poses = []<EOL>nr = <NUM_LIT:1>  <EOL>for _ in range(max_iter):<EOL><INDENT>if (nr != <NUM_LIT:0>) or (always_check_remove):<EOL><INDENT>nr, rposes = remove_bad_particles(st, **kwargs)<EOL><DEDENT>na, aposes = add_missing_particles(st, **kwargs)<EOL>current_changed = na + nr<EOL>removed_poses.extend(rposes)<EOL>added_poses0.extend(aposes)<EOL>total_changed += current_changed<EOL>_change_since_opt += current_changed<EOL>if current_changed == <NUM_LIT:0>:<EOL><INDENT>break<EOL><DEDENT>elif _change_since_opt > max_npart:<EOL><INDENT>_change_since_opt *= <NUM_LIT:0><EOL>CLOG.info('<STR_LIT>')<EOL>opt.do_levmarq(st, opt.name_globals(st, remove_params=st.get(<EOL>'<STR_LIT>').params), max_iter=<NUM_LIT:1>, run_length=<NUM_LIT:4>, num_eig_dirs=<NUM_LIT:3>,<EOL>max_mem=max_mem, eig_update_frequency=<NUM_LIT:2>, rz_order=<NUM_LIT:0>,<EOL>use_accel=True)<EOL>CLOG.info('<STR_LIT>'.format(st.error))<EOL><DEDENT><DEDENT>for p in added_poses0:<EOL><INDENT>i = st.obj_closest_particle(p)<EOL>opt.do_levmarq_particles(st, np.array([i]), max_iter=<NUM_LIT:2>, damping=<NUM_LIT>)<EOL>added_poses.append(st.obj_get_positions()[i])<EOL><DEDENT>return total_changed, np.array(removed_poses), np.array(added_poses)<EOL>

Automatically adds and subtracts missing & extra particles.

Operates by removing bad particles then adding missing particles on
repeat, until either no particles are added/removed or after `max_iter`
attempts.

Parameters
----------
st: :class:`peri.states.State`
    The state to add and subtract particles to.
max_iter : Int, optional
    The maximum number of add-subtract loops to use. Default is 7.
    Terminates after either max_iter loops or when nothing has changed.
max_npart : Int or 'calc', optional
    The maximum number of particles to add before optimizing the non-psf
    globals. Default is ``'calc'``, which uses 5% of the initial number
    of particles.
max_mem : Int, optional
    The maximum memory to use for optimization after adding max_npart
    particles. Default is 2e8.
always_check_remove : Bool, optional
    Set to True to always check whether to remove particles. If ``False``,
    only checks for removal while particles were removed on the previous
    attempt. Default is False.

Other Parameters
----------------
invert : Bool, optional
    ``True`` if the particles are dark on a bright background, ``False``
    if they are bright on a dark background. Default is ``True``.
min_rad : Float, optional
    Particles with radius below ``min_rad`` are automatically deleted.
    Default is ``'calc'`` = median rad - 25* radius std.
max_rad : Float, optional
    Particles with radius above ``max_rad`` are automatically deleted.
    Default is ``'calc'`` = median rad + 15* radius std, but you should
    change this for your particle sizes.

min_edge_dist : Float, optional
    Particles closer to the edge of the padded image than this are
    automatically deleted. Default is 2.0.
check_rad_cutoff : 2-element float list.
    Particles with ``radii < check_rad_cutoff[0]`` or ``> check...[1]``
    are checked if they should be deleted (not automatic). Default is
    ``[3.5, 15]``.
check_outside_im : Bool, optional
    Set to True to check whether to delete particles whose positions are
    outside the un-padded image.

rad : Float, optional
    The initial radius for added particles; added particles radii are
    not fit until the end of ``add_subtract``. Default is ``'calc'``,
    which uses the median radii of active particles.

tries : Int, optional
    The number of particles to attempt to remove or add, per iteration.
    Default is 50.

im_change_frac : Float, optional
    How good the change in error needs to be relative to the change in
    the difference image. Default is 0.2; i.e. if the error does not
    decrease by 20% of the change in the difference image, do not add
    the particle.

min_derr : Float, optional
    The minimum change in the state's error to keep a particle in the
    image. Default is ``'3sig'`` which uses ``3*st.sigma``.

do_opt : Bool, optional
    Set to False to avoid optimizing particle positions after adding.
minmass : Float, optional
    The minimum mass for a particle to be identified as a feature,
    as used by trackpy. Defaults to a decent guess.

use_tp : Bool, optional
    Set to True to use trackpy to find missing particles inside the
    image. Not recommended since trackpy deliberately cuts out particles
    at the edge of the image. Default is ``False``.

Returns
-------
total_changed : Int
    The total number of adds and subtracts done on the data. Not the
    same as ``changed_inds.size`` since the same particle or particle
    index can be added/subtracted multiple times.
added_positions : [N_added,3] numpy.ndarray
    The positions of particles that have been added at any point in the
    add-subtract cycle.
removed_positions : [N_added,3] numpy.ndarray
    The positions of particles that have been removed at any point in
    the add-subtract cycle.

Notes
------
Occasionally after the intial featuring a cluster of particles is
featured as 1 big particle. To fix these mistakes, it helps to set
max_rad to a physical value. This removes the big particle and allows
it to be re-featured by (several passes of) the adds.

The added/removed positions returned are whether or not the position
has been added or removed ever. It's possible that a position is
added, then removed during a later iteration.


def add_subtract_locally(st, region_depth=<NUM_LIT:3>, filter_size=<NUM_LIT:5>, sigma_cutoff=<NUM_LIT:8>,<EOL>**kwargs):

<EOL>tiles = identify_misfeatured_regions(<EOL>st, filter_size=filter_size, sigma_cutoff=sigma_cutoff)<EOL>n_empty = <NUM_LIT:0><EOL>n_added = <NUM_LIT:0><EOL>new_poses = []<EOL>for t in tiles:<EOL><INDENT>curn, curinds = add_subtract_misfeatured_tile(st, t, **kwargs)<EOL>if curn == <NUM_LIT:0>:<EOL><INDENT>n_empty += <NUM_LIT:1><EOL><DEDENT>else:<EOL><INDENT>n_added += curn<EOL>new_poses.extend(st.obj_get_positions()[curinds])<EOL><DEDENT>if n_empty > region_depth:<EOL><INDENT>break  <EOL><DEDENT><DEDENT>else:  <EOL><INDENT>pass<EOL><DEDENT>return n_added, new_poses<EOL>

Automatically adds and subtracts missing particles based on local
regions of poor fit.

Calls identify_misfeatured_regions to identify regions, then
add_subtract_misfeatured_tile on the tiles in order of size until
region_depth tiles have been checked without adding any particles.

Parameters
----------
st: :class:`peri.states.State`
    The state to add and subtract particles to.
region_depth : Int
    The minimum amount of regions to try; the algorithm terminates if
    region_depth regions have been tried without adding particles.

Other Parameters
----------------
filter_size : Int, optional
    The size of the filter for calculating the local standard deviation;
    should approximately be the size of a poorly featured region in each
    dimension. Best if odd. Default is 5.
sigma_cutoff : Float, optional
    The max allowed deviation of the residuals from what is expected,
    in units of the residuals' standard deviation. Lower means more
    sensitive, higher = less sensitive. Default is 8.0, i.e. one pixel
    out of every ``7*10^11`` is mis-identified randomly. In practice the
    noise is not Gaussian so there are still some regions mis-
    identified as improperly featured.
rad : Float or 'calc', optional
    The initial radius for added particles; added particles radii are
    not fit until the end of add_subtract. Default is ``'calc'``, which
    uses the median radii of active particles.
max_iter : Int, optional
    The maximum number of loops for attempted adds at one tile location.
    Default is 3.
invert : Bool, optional
    Whether to invert the image for feature_guess. Default is ``True``,
    i.e. dark particles on bright background.
max_allowed_remove : Int, optional
    The maximum number of particles to remove. If the misfeatured tile
    contains more than this many particles, raises an error. If it
    contains more than half as many particles, throws a warning. If more
    than this many particles are added, they are optimized in blocks of
    ``max_allowed_remove``. Default is 20.
im_change_frac : Float, between 0 and 1.
    If adding or removing a particle decreases the error less than
    ``im_change_frac *`` the change in the image, the particle is deleted.
    Default is 0.2.
min_derr : Float
    The minimum change in the state's error to keep a particle in the
    image. Default is ``'3sig'`` which uses ``3*st.sigma``.
do_opt : Bool, optional
    Set to False to avoid optimizing particle positions after adding
    them. Default is True
minmass : Float, optional
    The minimum mass for a particle to be identified as a feature, as
    used by trackpy. Defaults to a decent guess.
use_tp : Bool, optional
    Set to True to use trackpy to find missing particles inside the
    image. Not recommended since trackpy deliberately cuts out
    particles at the edge of the image. Default is False.
max_allowed_remove : Int, optional
    The maximum number of particles to remove. If the misfeatured tile
    contains more than this many particles, raises an error. If it
    contains more than half as many particles, throws a warning. If more
    than this many particles are added, they are optimized in blocks of
    ``max_allowed_remove``. Default is 20.

Returns
-------
n_added : Int
    The change in the number of particles; i.e the number added - number
    removed.
new_poses : List
    [N,3] element list of the added particle positions.

Notes
-----
Algorithm Description

1. Identify mis-featured regions by how much the local residuals
   deviate from the global residuals, as measured by the standard
   deviation of both.
2. Loop over each of those regions, and:

   a. Remove every particle in the current region.
   b. Try to add particles in the current region until no more
      can be added while adequately decreasing the error.
   c. Terminate if at least region_depth regions have been
      checked without successfully adding a particle.

Because this algorithm is more judicious about chooosing regions to
check, and more aggressive about removing particles in those regions,
it runs faster and does a better job than the (global) add_subtract.
However, this function usually does not work better as an initial add-
subtract on an image, since (1) it doesn't check for removing small/big
particles per se, and (2) when the poorly-featured regions of the image
are large or when the fit is bad, it will remove essentially all of the
particles, taking a long time. As a result, it's usually best to do a
normal add_subtract first and using this function for tough missing or
double-featured particles.


def optimize_particle(state, index, method='<STR_LIT>', doradius=True):

blocks = state.param_particle(index)<EOL>if not doradius:<EOL><INDENT>blocks = blocks[:-<NUM_LIT:1>]<EOL><DEDENT>g = state.gradloglikelihood(blocks=blocks)<EOL>if method == '<STR_LIT>':<EOL><INDENT>h = state.jtj(blocks=blocks)<EOL><DEDENT>if method == '<STR_LIT>':<EOL><INDENT>h = state.hessloglikelihood(blocks=blocks)<EOL><DEDENT>step = np.linalg.solve(h, g)<EOL>h = np.zeros_like(g)<EOL>for i in range(len(g)):<EOL><INDENT>state.update(blocks[i], state.state[blocks[i]] - step[i])<EOL><DEDENT>return g,h<EOL>

Methods available are
    gn : Gauss-Newton with JTJ (recommended)
    nr : Newton-Rhaphson with hessian

if doradius, also optimize the radius.


def rosenbrock_gendd(xd, A=<NUM_LIT:10>, order=<NUM_LIT:3>):

xp = xd[<NUM_LIT:1>:]<EOL>xi = xd[:-<NUM_LIT:1>]<EOL>r1 = A*(xp - xi**order)<EOL>r2 = <NUM_LIT:1> - xi<EOL>return np.append(r1, r2)<EOL>

A higher-dimensional modification of a generalized rosenbrock
function, as a set of residuals (cost = sum(residuals**2))

The standard modified function is with data = zeros(N), with a
global minimum at xd=ones(d). This function is a coupled model,
polynomial in the first d-1 parameters. Its data-space dimension
(2d-2) is greater than its model-space dimension (d) for d > 2.

Parameters
----------
    - xd : d-element list-like
        The x,y parameters of the model.
    - order : Int, optional
        The order of the model nonlinearity. Default is 3

Returns
-------
    (2d-2)-element list-like
        The residuals of the model.

Notes
-----
    Based on the multidimensional variation
        f(x) = \sum_{i=1}^{N-1} 100(x_{i+1} - x_i&2) + (1-x_i)^2
This gives a data space of dimension 2*(N-1) =2N-2 and a parameter
space of dimension N. According to wikipedia, the quadratic version
has 1 minimia for N=3 at (1,1,1), 2 minima for 4<=N<=7. See:
https://en.wikipedia.org/wiki/Rosenbrock_function#Multidimensional_generalisations


x, y = xy<EOL>r1 = x*x + y<EOL>r2 = y*y + x<EOL>return np.array([r1, r2])<EOL>

Himmelblau's function, as a set of residuals (cost = sum(residuals**2))

The standard Himmelbau's function is with data as [11, 7], and four
minimum at (3.0, 2.0), ~(-2.8, 3.1), ~(-3.8, -3.3), ~(3.6, -1.8).
Himmelblau's function is a quadratic model in both x and y. Its data-
space dimension (2) is equal to its model-space dimension (2), so
there is only parameter-effect curvature.

Parameters
----------
    - xy : 2-element list-like
        The x,y parameters of the model.

Returns
-------
    2-element list-like
        The residuals of the model.
Notes
------
https://en.wikipedia.org/wiki/Himmelblau%27s_function


x, y = xy<EOL>r1 = x - x*y<EOL>r2 = x - x*y*y<EOL>r3 = x - x*y*y*y<EOL>return np.array([r1, r2, r3])<EOL>

The Beale function, as a set of residuals (cost = sum(residuals**2))

The standard Beale's function is with data as [1.5, 2.25, 2.625],
and has a global minima at (3, 0.5). Beale's function is a coupled
model, linear in x and quartic in y. Its data-space dimension (3) is
greater than its model-space dimension (2).

Parameters
----------
    - xy : 2-element list-like
        The x,y parameters of the model.

Returns
-------
    3-element list-like
        The residuals of the model.


x, y = xy<EOL>r1 = x + <NUM_LIT:2>*y<EOL>r2 = y + <NUM_LIT:2>*x<EOL>return np.array([r1, r2])<EOL>

The Booth's function, as a set of residuals (cost = sum(residuals**2))

The standard Booth function is with data as [7, 5], and has a single
global minimum at (1,3). It is a coupled linear model, with the
parameter and data space both 2-dimensional.

Parameters
----------
    - xy : 2-element list-like
        The x,y parameters of the model.

Returns
-------
    2-element list-like
        The residuals of the model.


return xy<EOL>

A simple sphere, as a set of residuals (cost = sum(residuals**2))

Simply returns the input parameters. A linear, uncoupled model.

Parameters
----------
    - xy : 2-element list-like
        The x,y parameters of the model.

Returns
-------
    - xy : 2-element list-like
        The residuals, which are just xy


def rosenbrock_gen(xy, A=<NUM_LIT:10>, order=<NUM_LIT:3>):

x, y = xy<EOL>r1 = x<EOL>r2 = A*(y-x**order / order)<EOL>return np.array([r1, r2])<EOL>

A generalized rosenbrock banana function, as a set of residuals
(cost = sum(residuals**2))

The Rosenbrock function, generalized from a quadratic model to a
higher-order nonlinearity. The residuals are
    r1 = xy[0]
    r2 = xy[1] - xy[0]^n/n
The original function is with data = [1,0] and order=2, and has a
single minimum at (x,y) = (1, 1/order). The model is coupled,
polynomial in x and linear in y. Its data-space dimension (2) is
equal to its model-space dimension (2), so there is only parameter-
effect curvature. (See M Transtrum et al, PRE 2011)

Parameters
----------
    - xy : 2-element list-like
        The x,y parameters of the model.
    - order : Int, optional
        The order of the model nonlinearity. Default is 3

Returns
-------
    2-element list-like
        The residuals of the model.


def tile_overlap(inner, outer, norm=False):

div = <NUM_LIT:1.0>/inner.volume if norm else <NUM_LIT:1.0><EOL>return div*(inner.volume - util.Tile.intersection(inner, outer).volume)<EOL>


def separate_particles_into_groups(s, region_size=<NUM_LIT>, bounds=None):

imtile = (<EOL>s.oshape.translate(-s.pad) if bounds is None else<EOL>util.Tile(bounds[<NUM_LIT:0>], bounds[<NUM_LIT:1>])<EOL>)<EOL>region = util.Tile(region_size, dim=s.dim)<EOL>trange = np.ceil(imtile.shape.astype('<STR_LIT:float>') / region.shape)<EOL>translations = util.Tile(trange).coords(form='<STR_LIT>')<EOL>translations = translations.reshape(-<NUM_LIT:1>, translations.shape[-<NUM_LIT:1>])<EOL>groups = []<EOL>positions = s.obj_get_positions()<EOL>for v in translations:<EOL><INDENT>tmptile = region.copy().translate(region.shape * v - s.pad)<EOL>groups.append(find_particles_in_tile(positions, tmptile))<EOL><DEDENT>return [g for g in groups if len(g) > <NUM_LIT:0>]<EOL>

Given a state, returns a list of groups of particles. Each group of
particles are located near each other in the image. Every particle
located in the desired region is contained in exactly 1 group.

Parameters:
-----------
s : state
    The PERI state to find particles in.

region_size: int or list of ints
    The size of the box. Groups particles into boxes of shape region_size.
    If region_size is a scalar, the box is a cube of length region_size.
    Default is 40.

bounds: 2-element list-like of 3-element lists.
    The sub-region of the image over which to look for particles.
        bounds[0]: The lower-left  corner of the image region.
        bounds[1]: The upper-right corner of the image region.
    Default (None -> ([0,0,0], s.oshape.shape)) is a box of the entire
    image size, i.e. the default places every particle in the image
    somewhere in the groups.

Returns:
-----------
particle_groups: list
    Each element of particle_groups is an int numpy.ndarray of the
    group of nearby particles. Only contains groups with a nonzero
    number of particles, so the elements don't necessarily correspond
    to a given image region.


default = os.path.join(os.path.expanduser("<STR_LIT>"), "<STR_LIT>")<EOL>return os.environ.get('<STR_LIT>', default)<EOL>

The configuration file either lives in ~/.peri.json or is specified on the
command line via the environment variables PERI_CONF_FILE


out = {}<EOL>for k,v in iteritems(os.environ):<EOL><INDENT>if transform(k) in default_conf:<EOL><INDENT>out[transform(k)] = v<EOL><DEDENT><DEDENT>return out<EOL>

Read all environment variables to see if they contain PERI