# Source code documentation¶

## grow_tree.py module¶

grow_tree.py is the main module of the code and the one you invoke from the command line to start a simulation.

To start a simulation with parameters read from a file simulation.ini simply invoke this module as:

python grow_tree.py simulation.ini

The output will be written in a file name simulation.h5 with a HDF5 format.

Performs a step of duration dt but divides it into sub steps to make sure that the length of a channel is never longer than MAX_STEP.

grow_tree.external_field(r)[source]

Calculates the external field at points r. This is calculated from EXTERNAL_FIELD and ELECTRODE_POTENTIAL. As the code stands now only these two possibilities are physically meaningful:

1. Specify EXTERNAL_FIELD with a planar electrode or with no electrode, but use ELECTRODE_POTENTIAL=0.
2. ELECTRODE_POTENTIAL != 0, but ELECTRODE_GEOMETRY = 'sphere' and EXTERNAL_FIELD = 0.

However, we allow the user to shoot himself on his foot, so he can select any arbitrary combination of these parameters. Beware.

grow_tree.external_potential(r)[source]

Calculates the external potential at points r. See above, in external_field for the risks here.

grow_tree.init_electrode()[source]

Uses the input parameters to select an electrode geometry.

grow_tree.init_from_scratch(n=0)[source]

Init a ‘tree’ with the root node plus n additional nodes in a vertical string.

grow_tree.main()[source]

This is the main function of the code it is the starting point of a simulation.

grow_tree.rand(d0, d1, ..., dn)

Random values in a given shape.

Create an array of the given shape and propagate it with random samples from a uniform distribution over [0, 1).

d0, d1, ..., dn : int, optional
The dimensions of the returned array, should all be positive. If no argument is given a single Python float is returned.
out : ndarray, shape (d0, d1, ..., dn)
Random values.

random

This is a convenience function. If you want an interface that takes a shape-tuple as the first argument, refer to np.random.random_sample .

>>> np.random.rand(3,2)
array([[ 0.14022471,  0.96360618],  #random
[ 0.37601032,  0.25528411],  #random
[ 0.49313049,  0.94909878]]) #random

grow_tree.randn(d0, d1, ..., dn)

Return a sample (or samples) from the “standard normal” distribution.

If positive, int_like or int-convertible arguments are provided, randn generates an array of shape (d0, d1, ..., dn), filled with random floats sampled from a univariate “normal” (Gaussian) distribution of mean 0 and variance 1 (if any of the $$d_i$$ are floats, they are first converted to integers by truncation). A single float randomly sampled from the distribution is returned if no argument is provided.

This is a convenience function. If you want an interface that takes a tuple as the first argument, use numpy.random.standard_normal instead.

d0, d1, ..., dn : int, optional
The dimensions of the returned array, should be all positive. If no argument is given a single Python float is returned.
Z : ndarray or float
A (d0, d1, ..., dn)-shaped array of floating-point samples from the standard normal distribution, or a single such float if no parameters were supplied.

random.standard_normal : Similar, but takes a tuple as its argument.

For random samples from $$N(\mu, \sigma^2)$$, use:

sigma * np.random.randn(...) + mu

>>> np.random.randn()
2.1923875335537315 #random


Two-by-four array of samples from N(3, 6.25):

>>> 2.5 * np.random.randn(2, 4) + 3
array([[-4.49401501,  4.00950034, -1.81814867,  7.29718677],  #random
[ 0.39924804,  4.68456316,  4.99394529,  4.84057254]]) #random

grow_tree.relax(box, tr, r, q0, dt)[source]

Relax the conductor tree.Tree tr for a time dt.

Arguments:

• tr: the tree.Tree instance containing the tree structure.
• r: an array containing the node locations.
• q0: an array containing the charges of the nodes.
• dt: the time step.
grow_tree.seed(seed=None)

Seed the generator.

This method is called when RandomState is initialized. It can be called again to re-seed the generator. For details, see RandomState.

seed : int or array_like, optional
Seed for RandomState.

RandomState

grow_tree.self_fields(tr, r, q)[source]

Calculates the fields created by the charges at the streamer tips on themselves.

grow_tree.step(tr, r, q0, dt, p=0.0)[source]

Performs an elementary step, including relaxation and advancing the channels.

Arguments:

• tr: the tree.Tree instance containing the tree structure.
• r: an array containing the node locations.
• q0: an array containing the charges of the nodes.
• dt: the time step.
grow_tree.symmetric_gaussian(dr, sigma)[source]

Samples a branch from a symmetric, gaussian branching model. In a plane perpendicular to dr we sample dr1 from a cylindrically symmetric gaussian distribution; the two branching points are dr1 and its symmetric vector wrt dr.

grow_tree.velocities(box, tr, r, q)[source]

Calculates the electric fields at the tips of the tree and from them obtains the propagation velocities of the streamers

## parameters.py module¶

This is the parameter description file. Basically it provides a namespace where we store a function per input parameter. Each function receives a string and is responsible for converting to the appropriate type, checking for allowed values. The docstring of the function is a description of the parameter.

parameters.branch_in_xz(s)[source]

If true, branches always within the XZ plane.

parameters.desc(s)[source]

A comment to describe this simulation. It is ignored by the code.

parameters.dummy(s)[source]

This parameter is completely ignored. It is used only to produce series of identical runs.

parameters.electrode_geometry(s)[source]

The electrode geometry.

parameters.electrode_potential(s)[source]

Electrostatic potential of a (spherical) electrode.

parameters.end_with_reconnection(s)[source]

If true, finishes when a reconnection is detected

parameters.external_field(s)[source]

Externally applied electric field in the z direction.

parameters.fixed_branching_angle(s)[source]

If nonzero, fixes the angle between sibling branches.

parameters.max_step(s)[source]

Longest step for a channel in dt. The timestep will be reduced to satisfy this constraint

parameters.out_file(s)[source]

File name (including path) of the .h5 output file.

parameters.random_seed(s)[source]

Seed for the random generator. If < 0 the system time is used (default).

parameters.run_name(s)[source]

Name of the run.

parameters.single_branching_z(s)[source]

If nonzero, performs a single branching at the given z.

## tree.py module¶

This module contains the data representation for the structure of trees. Note that we separate the structure of the branched tree from its realization, that would contain things such as charges, positions, etc. that evolve even when the structure is fixed.

class tree.Segment[source]

This is class of the segments composing a Tree.

Adds the Segment other as a child of this segment.

get(a)[source]

Gets the value in array a corresponding to this segment.

Iterates over all adjacent segments, including parent and children (if any).

set(a, value)[source]

Sets the value in array a corresponding to this segment.

class tree.Tree[source]

Instances of the Tree class contain the topological information of a tree discharge: i.e. they encapsulate the relations between different segments in a tree but not about locations, conductivities etc..

Adds a segment to this tree. Returns the index of the segment inside the tree.

branch_distance(endpoints, dist=None, segment=None, lengths=None)[source]

Returns an array with the distance of each node from the branching immediately above it. The distance is calculated along the branch.

branch_label(labels=None, label=1, segment=None)[source]

Returns an array with an integer for each node that is unique for the branch where it sits.

branches()[source]

Finds all indices of segments that branch in the tree

extend(indices)[source]

Extends the tree adding one children to each segment indexed by indices, in that order. This is used to extend a propagating tree.

static from_parents(parents)[source]

Builds a tree from a list of the parent indices.

lengths(endpoints)[source]

Returns an array with the segment lengths of the tree, given an array with the endpoints.

Loads a tree structure from a txt file [DEBUG].

make_root()[source]

Creates a segment node to be root of this tree.

midpoints(endpoints)[source]

Returns an array with the segment midpoints of the tree, given an array with the endpoints.

ohm_matrix(endpoints, fix=[])[source]

Builds a matrix M that will provide the evolution of charges in every segment of the tree as dq/dt = M . phi, where phi is the potential at the center of each segment and ‘.’ is the dot product. This function builds the matrix from scratch. Usually it is much better to keep updating the matrix as the tree grows.

• endpoints must contain an array with the endpoints.
• fix contains an array with indices of nodes with a fixed charge. usually that means the root node.
parents(root_index=0)[source]

Builds an array with the indices to each segment’s parent. The root segment gets an index root_index.

reconnects(endpoints, rmin=0.0005, dmin=0.001)[source]

Finds reconnections in a tree.

save(fname)[source]

Saves the tree structure into file fname.

terminals()[source]

Finds all segments contained in the tree that do not have any children. Returns an array with segment indices.

zeros(dim=None)[source]

Returns an array that can hold all the data needed for a variable in this tree’s segments. For multi-dimension data, use dim.

tree.random_branching_tree(n, p)[source]

Builds a branched tree of n segments where every segment has a probability p of having two descendants. This produces nice pictures and can be useful for testing.

tree.sample_endpoints(tree)[source]

Gives endpoints to a tree structure. Useful for plotting sample trees [DEBUG].

tree.uniform()

random() -> x in the interval [0, 1).

## refinement.py module¶

This module implement the structure of oct-trees for the implementation of the Fast Multipolar Method (FMM).

. note:

Most of this code is not used, since we disabled the use of the FMM for
the simulations reported in the paper.  However, the simulated tree is
embedded in a bounding box defined by a :class:Box instance.
class refinement.Box(r0, r1, parent=None, rel_coords=None, electrode=None)[source]

Class of 3d boxes. Each box can be linked to a set of charges.

build_lists(recurse=False)[source]

Builds the lists of near-neighbours and the interaction list of this box. Assumes that the near-neighbours are already calculated up in the tree.

collect()[source]

Collects the multipolar expansions of this box’s children, translate them to the center and sums them.

collect_inward()[source]

Calculates the inward (local) expansions of all boxes in the interaction list and adds them.

collect_solutions(field=False)[source]

Collects the solution for each of the box’s children.

downward()[source]

Performs the “Downward Pass” of the Greengard papers.

eval_subtree(other)[source]

DEBUG purposes only.

expand(p)[source]

Directly calculates the multipolar expansion of this box around its center.

is_near_neighbour(other)[source]

Checks whether other is a near neighbour of this box. Note that they must belong to the same oct-tree or the algorithm fails.

refine()[source]

Creates the 8 children of the box.

set_charges(r, q, max_charges=None, min_length=0, evaluation=True)[source]

Sets the charges of this box. If max_charges is not None, refines the box into smaller children until each leaf box contains no more than max_charges. If evaluation is true, assumes that the charge points will also be the evaluation points.

set_evaluation(rv)[source]

Recursively sets the points where the potential will be evaluated.

set_field_evaluation(rf)[source]

Recursively sets the points where the fields will be evaluated.

solve(a, field=False)[source]

Once we have the local expansion for the box and the list of near-neighbours, we can finally evaluate the potential. Note that generally this function is called only for leaf nodes.

solve_all(a=0.0, **kwargs)[source]

Calls solve for the leaf nodes of the sub-tree rooted at self.

update_charges(q)[source]

Recursively re-set the charges contained in the box. This keeps the refinement oct-tree.

upward(p)[source]

Goes through the oct-tree. For leaves of the tree, directly calculates the multipole expansion; for nodes with descendants calculates the expansion by adding the children’s expansion. This is called “Upward Pass” in the Greengard papers.

refinement.containing_box(r, electrode=None)[source]

Builds a Box object that contains all k points in r[3, k]. The Box has to be a perfect cube for the FMM to work. If reflect is True, inludes also the reflection of all points over the z=0 plane.

This is an auxiliary module for reading input .ini files. It is based on Python’s stdlib ConfigParser

This module also provides functionality for setting run sets where one or more of the parameters run over a list of values.

Expands special characters to produce e.g. lists of many parameters.

Takes a dictionary that may contain a few lists as values and returns an iterator over dictionaries where each of these elements is iterated.

Expands an input file by expanding some of its arguments.

Converts s into int or float if possible. If not, leave it as a string. This will give us problems if the user wants to e.g. use filenames or run names that can be parser as a number. So have to implement a better approach whereby parameter names are associated with types.

Loads an input file and stores its values in the dictionary d. If upper is true, transforms the parameter names to upper case.

A decorator to constraint the parameter to nonnegative values.