BioSim1D – Reference Guide

This guide is for versions 1.0.0rc.6+ (Release Candidate)


4 classes: System1D, BioSim1D, Membranes1D, Diffusion1D. End users will typically instantiate BioSim1D

Source code

Class System1D

    The foundational structure of 1D systems,
    including bins, system state (concentrations and system time),
    and the underlying "ChemData" object.

    This base class does NOT know about membranes or reactions;
    nor does it handle any simulation.
    End users will typically instantiate the derived class BioSim1D
    
nameargumentsreturns
__init__n_bins :int, chem_data

        :param n_bins:      The number of compartments (bins) to model our 1D system
        :param chem_data:   Object of class "ChemData"
        

VIEW UPDATE SYSTEM

nameargumentsreturns
system_sizeint
        Return the number of bins in the system
        Note: the bin numbers will range between 0 and (system_size - 1)

        :return:    The number of bins in the system
        
nameargumentsreturns
get_system_timeprecision=8float
        Return the current system time

        :param precision:   Desired number of decimal digits
        :return:            The current system time
        
nameargumentsreturns
describe_stateconcise=FalseUnion[pd.DataFrame, None]
        Either a simple printout of the state of the system ("concise" option)
        or a more detailed printout with a returned Pandas data frame (not "concise")

        EXAMPLE (concise):
            SYSTEM STATE at Time t = 0:
            [[0. 0. 0. 0.]
             [0. 0. 0. 0.]]
            Membranes: [(1, 2)]

        EXAMPLE (not concise):
            SYSTEM STATE at Time t = 0:
            4 bins and 2 chemical species
            Membranes present:  [(12, 25)]
            

        :param concise: If True, only produce a minimalist printout with just the concentration values
        :return:        None, if concise=True;
                            a Pandas dataframe otherwise
        
nameargumentsreturns
get_chem_data
        Return all the associated chemical data,
        incl. diffusion rate constants (but EXCLUSIVE of reactions)

        :return:    An Object of type "ChemData"
        
nameargumentsreturns
assert_valid_binbin_address: intNone
        Raise an Exception if the given bin number isn't valid

        :param bin_address: An integer that ought to be between 0 and (self.n_bins-1), inclusive
        :return:            None
        
nameargumentsreturns
total_chem_masschem_label=None, chem_index=Nonefloat
        Return the sum of all the concentrations of the specified chemical,
        across all bins

        :param chem_label:  String with the label to identify the chemical of interest
        :param chem_index:  Integer to identify the chemical of interest.
                                Cannot specify both `chem_label` and `chem_index`

        :return:            True if this validation passes, or False otherwise
        
nameargumentsreturns
check_mass_conservationexpected :float, chem_label=None, chem_index=Nonebool
        Check whether the sum of all the concentrations of the specified chemical,
        across all bins, adds up to the passed value

        :param expected:    Value that the sum of all the bin concentrations of the specified chemical should add up to
        :param chem_label:  String with the label to identify the chemical of interest
        :param chem_index:  Integer to identify the chemical of interest.
                                Cannot specify both `chem_label` and `chem_index`

        :return:            True if this validation passes, or False otherwise
        
nameargumentsreturns
save_systemdict
        For now, just return a copy of self.system, with a "frozen" snapshot of the current system state

        :return:    A dict of (for now a part of) the elements needed to later restore the complete system state
        
nameargumentsreturns
snapshot_systemcopy=Truedict
        Return a "frozen" snapshot of the current system state

        :param copy:    If True (default), a copy is made of arrays;
                            otherwise, the "snapshot" is not a fixed entity - and will change if the system is updated!
        :return:        A dict of (for now a part of) the elements needed to later restore the complete system state
        
nameargumentsreturns
restore_systemnew_state: dictNone
        Replace (some, for now, of) the various parts the System's internal state.
        For details of the data structure, see the class variable "system"

        :param new_state:   Numpy array containing the desired new System's internal state
        :return:            None
        
nameargumentsreturns
replace_systemnew_state: np.arrayNone
        Replace the System's internal state.
        For details of the data structure, see the class variable "system"
        IMPORTANT: membranes aren't handled. System length and global_Dx are currently not modified

        :param new_state:   Numpy array containing the desired new System's internal state
        :return:            None
        

SPATIAL ELEMENTS RESOLUTION

nameargumentsreturns
set_dimensionslengthNone
        Set the overall length of the system.
        Doing so, will permit to convert bin numbers to positional values

        :param length:
        :return:
        
nameargumentsreturns
x_coordbin_address
        Return the x coordinate of the middle of the specified bin.
        By convention, for the leftmost bin, it's zero,
        and for the rightmost, it's the overall length of the system
        
nameargumentsreturns
increase_spatial_resolutionfactor:intNone
        Increase the spatial resolution of the system by cloning and repeating
        each bin, by the specified number of times.
        Replace the System's internal state
        (note that the number of bins will increase by the requested factor)

        EXAMPLE: if the (2-chemicals) system is
                        [[11. 12. 13.]
                         [ 5. 15. 25.]]
                and factor=2, then the result will be
                        [[11. 11. 12. 12. 13. 13.]
                         [ 5.  5. 15. 15. 25. 25.]]

        :param factor:  Number of bins into which to split each bin (replicating their concentration values)
        :return:        None
        
nameargumentsreturns
double_spatial_resolution_linearNone
        Increase the spatial resolution of the system by inserting between bins
        their average value (of concentrations, for every chemical species.)
        Replace the System's internal state
        (note that if the number of bins is initially N, it'll become 2N-1).
        If the system has fewer than 2 bins, an Exception will be raised.

        EXAMPLE: if the (2-chemicals) system is
                        [[11. 12. 13.]
                         [ 5. 15. 25.]]
                then the result will be
                        [[11.  11.5 12.  12.5 13. ]
                         [ 5.  10.  15.  20.  25. ]]

        :return:    None
        
nameargumentsreturns
decrease_spatial_resolutionfactor:intNone
        EXAMPLE: if the system is
                        [[10., 20., 30., 40., 50., 60.]
                         [ 2., 8.,   5., 15., 4.,   2.]]
                and factor=2, then the result will be
                        [[15., 35., 55.]
                         [ 5., 10.,  3.]]

        :param factor:
        :return:
        
nameargumentsreturns
smooth_spatial_resolutionNone
        EXAMPLE: if the system is
                        [[10., 20., 30.]
                         [ 2., 8.,   4.]]
                then the result will be
                        [[10., 15., 20., 25., 30.]
                         [ 2.,  5.,  8.,  6.,  4.]]

        :return:
        

SET MODIFY CONCENTRATIONS

nameargumentsreturns
set_uniform_concentrationconc: float, chem_index=None, chem_label=NoneNone
        Assign the given concentration to all the bins of the specified chemical (identified by its index or name.)
        Any previous values get over-written

        :param conc:        The desired value of chemical concentration for the above species
        :param chem_index:  [DEPRECATED] Zero-based index to identify a specific chemical
        :param chem_label:  [OPTIONAL] If provided, it over-rides the value for chem_index
        :return:            None
        
nameargumentsreturns
set_all_uniform_concentrationsconc_list: Union[list, tuple]None
        Set the concentrations of all chemical species at once, uniformly across all bins

        :param conc_list:   List or tuple of concentration values for each of the chemical species,
                                in their index order
        :return:            None
        
nameargumentsreturns
set_bin_concbin_address: int, conc: float, chem_index=None, chem_label=NoneNone
        Assign the requested concentration value to the given bin, for the specified chemical species.

        :param bin_address:     The zero-based bin number of the desired compartment
        :param conc:            The desired concentration value to assign to the specified location
        :param chem_index:      DEPRECATED.  Zero-based index to identify a specific chemical species
        :param chem_label:      [OPTIONAL] If provided, it over-rides the value for chem_index
        :return:                None
        
nameargumentsreturns
set_species_concconc_list: Union[list, tuple, np.ndarray], chem_index=None, chem_label=NoneNone
        Assign the requested list of concentration values to all the bins, in bin order,
        for the specified single chemical species.

        :param conc_list:   A list, tuple or Numpy array with the desired concentration values
                                to assign to all the bins.
                                The dimensions must match the system's dimensions.
        :param chem_index:  DEPRECATED.  Zero-based index to identify a specific chemical species
        :param chem_label:  (OPTIONAL) If provided, it over-rides the value for chem_index
        :return:            None
        
nameargumentsreturns
inject_conc_to_binbin_address: int, delta_conc: float, chem_label=None, chem_index=None, zero_clip = FalseNone
        Add the requested concentration to the cell with the given address, for the specified chem species

        :param bin_address: The zero-based bin number of the desired cell
        :param chem_label:  String to identify the chemical of interest
        :param chem_index:  DEPRECATED.  Alternate way to identify the chemical of interest, with a zero-based index
        :param delta_conc:  The concentration to add to the specified location
        :param zero_clip:   If True, any requested increment causing a concentration dip below zero, will make the concentration zero;
                                otherwise, an Exception will be raised
        :return:                None
        
nameargumentsreturns
inject_gradientchem_label, conc_left = 0., conc_right = 0.None
        Add to the concentrations of the specified chemical species a linear gradient spanning across all bins,
        with the indicated values at the endpoints of the system.

        :param chem_label:  The name of the chemical whose concentration we're modifying
        :param conc_left:   The desired amount of concentration to add to the leftmost bin (the start of the gradient)
        :param conc_right:  The desired amount of concentration to add to the rightmost bin (the end of the gradient)
        :return:            None
        
nameargumentsreturns
inject_sine_concchem_label, number_cycles, amplitude, bias=0, phase=0, zero_clip = FalseNone
        Add to the current concentrations of the specified chemical species
        a sinusoidal signal across all bins.

        Note:   A sine wave of the form  f(x) = A sin(B x - C)
                has an amplitude of A, a period of 2Pi/B and a right phase shift of C (in radians)

        In Mathematica:  Plot[Sin[B x - C] /. {B -> 2 Pi, C -> 0} , {x, 0, 1}, GridLines -> Automatic]

        :param chem_label:       The name of the chemical whose concentration we're modifying
        :param number_cycles:   Number of full waves along the length of the system
        :param amplitude:       Amplitude of the Sine wave.  Note that peak-to-peak values are double the amplitude
        :param bias:            Amount to be added to all values (akin to "DC bias" in electrical circuits)
        :param phase:           In degrees: phase shift to the RIGHT.  EXAMPLE: 180 to flip the Sine curve
        :param zero_clip:       If True, any requested change causing a concentration dip below zero,
                                    will make the concentration zero;
                                    otherwise, an Exception will be raised
        :return:                None
        
nameargumentsreturns
inject_bell_curvechem_label, center=None, mean=0.5, sd=0.15, amplitude=None, max_amplitude=None, bias=0, clip=NoneNone
        Add to the current concentrations of the specified chemical species a signal across all bins in the shape of a Bell curve.
        The default values provide bell shape centered in the middle of the system, and fairly spread out
        (but pretty close to zero at the endpoints)

        :param chem_label:  The name of the chemical species whose concentration we're modifying
        :param center:      A value, generally between 0 and 1, indication the spatial position of the mean
                                relative to the bin system;
                                if less than 0 or greater than 1, only one tail of the curve will be seen
        :param mean:        [DEPRECATED: use `center` instead]
        :param sd:          Standard deviation, in units of the system length
        :param amplitude:   Amount by which to multiply the standard normal curve signal,
                                before adding it to current concentrations
                                Note: NOT the same as the max_amplitude of the bell curve; see next argument.
        :param max_amplitude:Largest value (EXCLUSIVE of bias) that the (smoothed version of the) bell curve reaches.
                                Only one of the 2 arguments `amplitude` and `max_amplitude` may be provided;
                                if neither is specified, `amplitude` is set to 1
        :param bias:        Positive amount to be added to all values (akin to "DC bias" in electrical circuits)
        :param clip:        [OPTIONAL] Pair of integers; any bin to the left of the 1st value,
                                or to the right of the 2nd value, will be left unmodified
        :return:            None
        

LOOKUP CONCENTRATIONS

nameargumentsreturns
chem_quantitychem_label=None, chem_index=Nonefloat
        Return the total quantity, across all bins, of the given chemical

        :param chem_label:
        :param chem_index:  DEPRECATED.
        :return:
        
nameargumentsreturns
lookup_specieschem_index=None, chem_label=None, copy=Falsenp.array
        Return the NumPy array of concentration values across the all bins (from left to right)
        for the single specified chemical species.
        NOTE: what is being returned NOT a copy, unless specifically requested

        :param chem_index:   DEPRECATED.  The index order of the chemical species of interest
        :param chem_label:   If provided, it over-rides the value for chem_index
        :param copy:         If True, an independent numpy array will be returned: a *copy* rather than a view
        :return:             A NumPy 1-D array of concentration values across the bins (from left to right);
                                the size of the array is the number of bins
        
nameargumentsreturns
system_snapshot_arrchem_label=None, chem_index=Nonenp.ndarray
        Return a snapshot (at the current system time) of all the concentrations
        of the given chemical species,
        across ALL BINS, as a 1D Numpy array.
        If a Pandas dataframe is desired, use system_snapshot()

        :param chem_label:  String with the label to identify the chemical of interest
        :param chem_index:  Integer to identify the chemical of interest.  Cannot specify both chem_label and chem_index
        :return:            A 1-D Numpy array of concentration values along bin coordinates
        
nameargumentsreturns
system_snapshotpd.DataFrame
        Return a snapshot  (at the current system time) of all the concentrations
        of ALL the chemical species, across all bins
        as a Pandas dataframe

        :return:    A Pandas dataframe: each row is a bin,
                        and each column a chemical species
        
nameargumentsreturns
bin_concentrationbin_address: int, chem_index=None, chem_label=Nonefloat
        Return the concentration at the requested bin of the specified chemical species

        :param bin_address: The bin number
        :param chem_index:  DEPRECATED.  The index order of the chemical species of interest
        :param chem_label:  If provided, it over-rides the value for chem_index
        :return:            A concentration value at the indicated bin, for the requested species
        
nameargumentsreturns
bin_snapshotbin_address: intdict
        Extract the concentrations of all the chemical species at the specified bin,
        as a dict whose keys are the names of the species
        EXAMPLE:  {'A': 10.0, 'B': 50.0}

        :param bin_address: An integer with the bin number
        :return:            A dict of concentration values; the keys are the names of the species
        
nameargumentsreturns
bin_snapshot_arraybin_address: intnp.array
        Extract the concentrations of all the chemical species at the specified bin,
        as a Numpy array in the index order of the species
        EXAMPLE: np.array([10., 50.)]

        :param bin_address: An integer with the bin number
        :return:            A Numpy array  of concentration values, in the index order of the species
        
nameargumentsreturns
show_system_snapshotpd.DataFrame
        Print a header, and return a dataframe

        :return:    A Pandas dataframe
        
nameargumentsreturns
selected_concentrationsbins=None, chem_labels=Nonedict
        Extract and return the concentration values of one or more chemicals,
        in one or more bins.
        The value is returned as a dictionary where the keys are bin addresses, and the values are dicts of
        concentration values for the various chemicals (identified by their labels)
            EXAMPLE:
                    {   5: {"A": 1.3, "B": 3.9},
                        8: {"A": 4.6, "B": 2.7}
                    }

        :param bins:        Bin address (integer), or list of bin addresses. Use None to indicate all
        :param chem_labels: Chemical label, or list of labels. Use None to indicate all
        :return:            A dict indexed by bin address
        

HISTORY

nameargumentsreturns
enable_historybins=None, frequency=1, chem_labels=None, take_snapshot=False, caption=NoneNone
        Request history capture, with the specified parameters.
        If history was already enabled, this function can be used to alter its capture parameters.

        :param bins:            Bin address (integer), or list of bin addresses. Use None to indicate all
        :param frequency:       [OPTIONAL] How many simulation cycles to wait until taking another data snapshot
        :param chem_labels:     [OPTIONAL] List of chemicals to include in the history;
                                    if None (default), include them all.
        :param take_snapshot:   If True, a snapshot of the system's current configuration
                                    is immediately added to the history
        :param caption:         [OPTIONAL] String to save alongside this snapshot, if taken (only applicable
                                    if `take_snapshot` is True

        :return:                None
        
nameargumentsreturns
capture_snapshotstep_count=None, caption=""None
        Preserve a pre-defined type of snapshot
        (some concentration values, based on specs specified at the time history was enabled),
        linked to the current System Time.

        :param step_count:  [OPTIONAL] Information about the simulation step, needed if history
                                is to be selectively captured, only every so many steps
        :param caption:     [OPTIONAL] String to save alongside this snapshot
        :return:            None
        
nameargumentsreturns
get_bin_historybin_address :int, include_captions=Truepd.DataFrame
        Get the concentration history at the given bin(s) of all the chemicals
        whose history was requested by a call of enable_history()

        :param bin_address:         A single bin address (an integer)
        :param include_captions:    If True, the captions are returned as an extra "caption" column at the end
        :return:                    A Pandas data frame
        
nameargumentsreturns
save_valuedata_snapshot: dict, caption =""None
        Preserve some data value (passed as dictionary) in the history, linked to the
        current System Time.

        Note: if wanting to routinely save system concentration values, use capture_snapshot() instead

        EXAMPLE:  save_value(data_snapshot = {"my value A": 12.5, "my value B": 3.7},
                              caption="Just prior to infusion")

        :param data_snapshot:   A dictionary of data to preserve for later use
        :param caption:         Optional caption to attach to this preserved data
        :return:                None
        
nameargumentsreturns
get_saved_valuespd.DataFrame
        Retrieve and return a Pandas dataframe with the system history that had been saved
        using save_value()

        IMPORTANT: not to be confused with the standard concentration history, obtained by a call to get_bin_history()

        :return:    A Pandas dataframe
        

VISUALIZATION

nameargumentsreturns
visualize_systemtitle_prefix=None, colors=None, plot_bg_color="oldlace", show=Falsepgo.Figure
        Visualize the current state of the system of all the chemicals as a combined line plot,
        using plotly.
        The x-axis is the bin coordinate, and the y-axis are the concentrations of each of the chemicals.
        An auto-generated title is included.
        If membranes are present, they will appear as brown vertical lines.

        :param title_prefix:[OPTIONAL] Prefix to the auto-generated title;
                                either a string,
                                or a list/tuple (2 entries) max to insert on separate lines
        :param colors:      [OPTIONAL] List of standardized color names to use for each of the chemicals.
                                If None, then use the registered colors (if present),
                                or the hardwired defaults as a last resort
        :param plot_bg_color:[OPTIONAL] The color inside the axes.  The default color used here is different from
                                Plotly standard color, to visually differentiate this kind of plots from other type
        :param show:        [OPTIONAL] If True, the plot will be shown.
                                Note: on JupyterLab, simply returning a plot object (without assigning it to a variable)
                                      leads to it being automatically shown

        :return:            A Plotly "Figure" object
        
nameargumentsreturns
system_heatmapschem_labels=None, colors=None, title_prefix ="", **kwargspgo.Figure

        :param chem_labels: [OPTIONAL] NOT YET USED.  For now, ALL chemicals get shown
        :param colors:      [OPTIONAL] If None, then use the registered colors (if specified),
                                or the hardwired defaults as a last resort
                                (but only if more than 1 chemical; if only 1, go monochromatic)
        :param title_prefix:[OPTIONAL] A string to prefix to the auto-generated title
        :param kwargs:      [OPTIONAL] Other named arguments to pass to PlotlyHelper.heatmap_stack_1D()
                                For list, see documentation of method PlotlyHelper.heatmap_stack_1D

        :return:            A Plotly "Figure" object containing a stack of Heatmaps
        
nameargumentsreturns
line_plotplot_pars: dict, graphic_component, header=None, color_mapping=NoneNone
        Send to the HTML log, a line plot representation of the concentrations of
        all the chemical species species.

        IMPORTANT: must first call GraphicLog.config(), or an Exception will be raised

        :param plot_pars:           A dictionary of parameters (such as "outer_width") for the plot
        :param graphic_component:   A string with the name of the graphic module to use.  EXAMPLE: "vue_curves_4"
        :param header:              [OPTIONAL] String to display just above the plot
        :param color_mapping:       [OPTIONAL] Dict mapping index numbers to color names or RBG hex values.
                                        If not provided, the colors associated to the chemicals are used, if any
        :return:                    None
        
nameargumentsreturns
plot_history_single_binbin_address :int, colors=None, title_prefix=None, title=None, smoothed=False, vertical_lines_to_add=None, max_points=Nonepgo.Figure
        Using plotly, draw the plots of chemical concentration values over time at the specified bin,
        based on the historical data that was saved when running simulations.

        Note: if this plot is to be later combined with others, use PlotlyHelper.combine_plots()

        :param bin_address: A single bin address (an integer)
        :param colors:      [OPTIONAL] List of CSS color names for each of the heatmaps.
                                If provided, its length must match that of the data;
                                if None, then use the registered colors (if specified),
                                or the hardwired defaults as a last resort
        :param title_prefix:[OPTIONAL] Prefix to the auto-generated title;
                                either a string,
                                or a list/tuple (2 entries) max to insert on separate lines
        :param title:       [OPTIONAL] If set, it over-rides `title_prefix.  If not passed, a default one is used
        :param smoothed:    [OPTIONAL] If True, a spline is used to smooth the lines;
                                otherwise (default), line segments are used
        :param vertical_lines_to_add: [OPTIONAL] List or tuple or Numpy array or Pandas series
                                    of x-coordinates at which to draw thin vertical dotted gray lines.
                                    If the number of vertical lines is so large as to overwhelm the plot,
                                    only a sample of them is shown.
                                    Note that vertical lines, if requested, go into the plot's "layout";
                                    as a result they might not appear if this plot is later combined with another one.
        :param max_points:  [OPTIONAL] Maximum number of points to include in the plot; if exceeded,
                                only an appropriate sampling of historical data is used,
                                and an informational message is printed out

        :return:            A plotly "Figure" object; an Exception is raised if no historical data is found
        



Class BioSim1D

    1D simulations of diffusion and reactions,
    with optional membranes
    
nameargumentsreturns
__init__n_bins :int, chem_data=None, reaction_handler=None, reactions=None
        Initialize all concentrations to zero.
        Membranes, if present, need to be set later.

        :param n_bins:          The number of compartments (bins) to use in the simulation

        [IMPORTANT: At least one of the 3 following arguments MUST be provided]
        :param chem_data:       [OPTIONAL] Object of class "ChemData";
                                    if not specified, it will get extracted
                                    from the "UniformCompartment" class (if passed to the next argument)
        :param reaction_handler:[OPTIONAL] Object of class "UniformCompartment";
                                    if not specified, it'll get instantiated here
        :param reactions:       [OPTIONAL] Object of type "Reactions", with data about the reactions and the chemicals
        

REACTIONS

nameargumentsreturns
get_reactions
        Return all the associated reactions

        :return:    Object ot type "Reactions" (with data about all the reactions)
        
nameargumentsreturns
get_reaction_handlerbin_address=0
        Return the object that manages the reactions.
        Note that for now just 1 object is present;
        in the future, it might be 1 per bin (or per bin cluster)

        :param bin_address: CURRENTLY NOT USED
        :return:            Object ot type "UniformCompartment"
        
nameargumentsreturns
reaction_in_equilibriumbin_address: int, rxn_index :int, tolerance=1, explain=Truebool
        Ascertain whether the given system concentrations are in equilibrium at the given bin,
        for the specified reactions (by default, check all reactions)

        :param bin_address: The zero-based bin number of the desired compartment
        :param rxn_index:   The integer index (0-based) to identify the reaction of interest;
                                if None, then check all the reactions
        :param tolerance:   Allowable relative tolerance, as a PERCENTAGE,
                                to establish satisfactory match with expected values
        :param explain:     If True, print out details about the analysis,
                                incl. the formula(s) being used to check the equilibrium
                                EXAMPLES:   "([C][D]) / ([A][B])"
                                            "[B] / [A]^2"

        :return:            Return True if ALL the reactions are close enough to an equilibrium,
                                as allowed by the requested tolerance;
                                otherwise, return a dict of the form {False: [list of reaction indexes]}
                                for all the reactions that failed the criterion
                                EXAMPLE:  {False: [3, 6]}
        

MEMBRANES

nameargumentsreturns
membranes

nameargumentsreturns
uses_membranesbool

nameargumentsreturns
set_membranesmembranes: ListNone

nameargumentsreturns
change_permeabilitychem_label :str, permeability :floatNone

nameargumentsreturns
set_permeabilitypermeability :dictNone


SIMULATIONS

nameargumentsreturns
diffusetotal_duration=None, time_step=None, n_steps=None, fraction_max_step=None, delta_x=1, algorithm=None, show_status=Falsedict
        Uniform-step diffusion, with up to 2 out of 3 criteria specified:

            1) until reaching, or just exceeding, the desired time duration
            2) using the given time step OR fraction_max_step
            3) making use of the specified number of steps

        If only the `total_duration` is specified, then a default is used for the step sizes

        :param total_duration:  The overall time advance (i.e. time_step * n_steps)
        :param time_step:       The size of each constant time step
        :param fraction_max_step: The fraction (> 0 and <= 1) of what is regarded as the max allowed step,
                                    based on stability considerations for the diffusion of the chemical with the
                                    largest diffusion rate
        :param n_steps:         The desired number of constant steps
        :param delta_x:         Distance between consecutive bins (the spatial dimension of each bin)
        :param algorithm:       [OPTIONAL] String indicating the desired method to use to solve the diffusion equation.
                                    Currently available options: "5_1_explicit";
                                    if not specified, the default method diffuse_step_single_species() is used
        :param show_status:     If True, the return value gets printed
                                    (note: in Jupyterlab, it gets automatically shown, if run as the last statement)

        :return:                A dictionary with data about the status of the operation
                                    "steps":        the number of steps that were run
                                    "system time":  the system time at the end of the operation
                                    "time_step":    the size of each time step
        
nameargumentsreturns
diffuse_steptime_step :float, delta_x=1, algorithm=NoneNone
        Diffuse all the chemical species for the given time step, across all bins;
        clear the self.delta_diffusion array, and then re-compute it from all the species.

        IMPORTANT: the actual system concentrations are NOT changed.

        :param time_step:   Time step over which to carry out the diffusion
                            If too large - as determined by the method is_excessive() - an Exception will be raised
        :param delta_x:     Spatial distance between consecutive bins
        :param algorithm:   [OPTIONAL] String indicating the desired method to use to solve the diffusion equation.
                                Currently available option: "5_1_explicit";
                                if not specified, the default method diffuse_step_single_species() is used
        :return:            None (the array in the class variable "delta_diffusion" gets set)
        
nameargumentsreturns
reacttotal_duration=None, time_step=None, n_steps=None, silent=FalseNone
        Update the system concentrations as a result of all the reactions in all bins - taking
        the presence of membranes into account, if applicable.

        CAUTION : NO diffusion is performed. Use this function
                  only if you intend to do reactions without diffusion!

        The duration and granularity of the reactions is specified with 2 out of the 3 parameters:
            total_duration, time_step, n_steps

        For each bin, or each membrane-separated side of bin, (or combined group of bins - not currently implemented),
        process all the reactions in it - based on
        the INITIAL concentrations (prior to this reaction step),
        which are used as the basis for all the reactions.

        Optionally, save some data from the individual reaction steps

        :param total_duration:  The overall time advance (i.e. time_step * n_steps)
        :param time_step:       The size of each time step
        :param n_steps:         The desired number of steps
        :param silent:
        :return:                None
        
nameargumentsreturns
reaction_stepdelta_time: floatNone
        Compute and store the incremental concentration changes in all bins,
        from all reactions,
        for a single time step of duration `delta_time`.

        The incremental concentration changes are stored in the class variable
        "delta_reactions", which contains a Numpy array that gets cleared and set.

        IMPORTANT: the actual system concentrations are NOT changed.

        For each bin, process all the reactions in it - based on
        the INITIAL concentrations (prior to this reaction step),
        which are used as the basis for all the reactions.

        :param delta_time:  The time duration of the reaction step - assumed to be small enough that the
                            concentration won't vary significantly during this span
        :return:            None (note: the class variable "delta_reactions" gets updated)
        
nameargumentsreturns
react_diffusetotal_duration=None, time_step=None, n_steps=None, fraction_max_step=None, delta_x = 1, show_status=Falsedict
         Uniform-step reaction-diffusion, with up to 2 out of 3 criteria specified:

            1) until reaching, or just exceeding, the desired time duration
            2) using the given time step OR fraction_max_step
            3) making use of the specified number of steps

        If only the `total_duration` is specified, then a default is used for the step sizes

        :param total_duration:  The overall time advance (i.e. time_step * n_steps)
        :param time_step:       The size of each constant time step
        :param fraction_max_step: The fraction (> 0 and <= 1) of what is regarded as the max allowed step,
                                    based on stability considerations for the diffusion of the chemical with the
                                    largest diffusion rate
        :param n_steps:         The desired number of constant steps
        :param delta_x:         Distance between consecutive bins  (the spatial dimension of each bin)
        :param show_status:     If True, the return value gets printed
                                    (note: in Jupyterlab, it gets automatically shown, if run as the last statement)

        :return:                A dictionary with data about the status of the operation
        

FOURIER ANALYSIS

nameargumentsreturns
frequency_analysischem_label: str, threshold = 0.001, n_largest = Nonepd.DataFrame
        Return the individual frequencies, and their relative amplitudes,
        in the concentration values of the specified chemical species.
        A Discrete Fourier Transform is used for the computation.

        :param chem_label:  The name of the chemical whose concentration we want to analyze
        :param threshold:   Minimum amplitudes of the frequency components to be considered non-zero
                                (NOTE: these are the raw values returned by the DFT - not the normalized ones.)
        :param n_largest:   If specified, only the rows with the given number of largest amplitudes gets returned
                                (if there are fewer rows to start with, they all get returned)

        :return:            A Pandas dataframe with 2 columns, "Frequency" and "Relative Amplitude";
                                amplitudes are relative the the smallest nonzero frequency (which is taken to be 1.0)
                                EXAMPLE:
                                               Frequency  Relative Amplitude
                                            0        0.0                 3.0
                                            1        2.0                 1.0
                                            2        4.0                 0.5
                                            3        8.0                 0.2
        



Class Membranes1D

    This class supports the underlying foundational class System1D, to provide modeling of membranes (barriers)

    * Only CLOSED membranes are modeled.
        In 1D, that's not well-defined, but we'll consider a PAIR of membranes (with no other membrane between them)
        to constitute a "closed membrane" for our purposes.

    * Membranes exist at the boundary between System bins.

    * Conceptually, a membrane is a list of "sides".
        Those "sides" collectively encompass a portion of the System space,
        and trace the  boundary of the closed membrane ("organelle")

    * "Sides":
        In 1D, the "sides" are points; in 2D, they are adjacent segments, and in 3D, rectangles.

        In 2D and 3D, the "sides" cannot lie diagonally (slanted) across the System space; they all must follow
        the directions of the axes (grid) of the System.

        The "sides" cannot intersect, or even touch, with any other "side"
        of the same membrane or of any other membrane.

    * Implementation:
        In 1D, a membrane is a list of exactly 2 points.
        Each point is identified by the coordinate of bin immediately to the RIGHT of it
        (or, if at the rightmost edge of the System, by the next integer of the coordinate of the bin to its left.)
        So, the "side" of a membrane at the leftmost position in the system will have the value 0.
        All integers must be between 0 and the total number of bins, both inclusive

        In 2D, a membrane "side" is a segment, and a membrane is a closed polygon.
        Each point of the polygon is identified by the coordinates
        of the bin immediately to its RIGHT and ABOVE (in xy-coordinates).
        So, a point at the leftmost/bottom position in the system will have the value (0,0)

        In 3D, a membrane "side" is a rectangle, defined by 4 consecutive points.
        Each point is identified by the coordinates of bin immediately past it (in xyz-coordinates)
    
nameargumentsreturns
__init__n_bins :int

        :param n_bins:  The number of compartments (bins) to model our 1D system
        
nameargumentsreturns
uses_membranesbool
        Return True if membranes are part of the system

        :return:    True if any membrane was created in the system; False otherwise
        
nameargumentsreturns
set_membranesmembranes: ListNone
        Define the position of all membranes in the system.

        IMPORTANT: any previously-set membrane information is lost.

        :param membranes:       List of pairs of bin coordinates.  Use an empty list to clear all membranes.
                                    All integer values must be between 0 and self.n_bins, both inclusive,
                                    and be sorted in increasing order order.
                                    Membrane positions are identified by the index of the bin to their RIGHT side.
                                    Membranes cannot intersect, nor touch!
                                    EXAMPLE: if the system contains bins 0 thru 30 (i.e 31 bins),
                                             then a possible list of membranes is  [ (0, 8) , (17, 31) ]
        :return:                None
        
nameargumentsreturns
set_permeabilitypermeability :dictNone
        Set the permeability of all membranes for various chemicals.
        For now, permeability is the same for all membranes,
        i.e. a function of only the chemicals.

        :param permeability:    Dictionary mapping chemical labels
                                    to the membranes' permeability to them (in passive transport)
        :return:                None
        
nameargumentsreturns
change_permeabilitychem_label :str, permeability :floatNone
        Use the specified value to set the permeability of all the membranes
        to given chemical

        :param chem_label:  A string to identify the chemical of interest
        :param permeability:The permeability of all membranes to that chemical
        :return:            None
        
nameargumentsreturns
membrane_on_leftbin_address :intbool
        Return True if there's a membrane to the immediate left of the given bin (specified by its index)

        :param bin_address:
        :return:
        
nameargumentsreturns
membrane_on_rightbin_address :intbool
        Return True if there's a membrane to the immediate right of the given bin (specified by its index)

        :param bin_address:
        :return:
        



Class Diffusion1D

    Module to model diffusion in 1D systems, with or without membranes.

    NOT meant for the end user!
    
nameargumentsreturns
__init__n_bins :int, membranes=None

        :param n_bins:      Total number of bins in the system
        :param membranes:   [OPTIONAL] Object of class "Membranes1D"
        
nameargumentsreturns
is_excessivetime_step :float, diff_rate :float, delta_x :floatbool
        Use a loose heuristic to determine if the requested time step is too long,
        given the diffusion rate and delta_x.
        This is also based on the "Von Neumann stability analysis"
        (an explanation can be found at: https://www.youtube.com/watch?v=QUiUGNwNNmo)

        :param time_step:   Duration of the time interval being TENTATIVELY used in the simulation step
        :param diff_rate:   The diffusion rate of the chemical under consideration
        :param delta_x:     The spatial dimension of the bin
        :return:            True if the time step is deemed excessive
                                based the heuristic implemented by the function max_time_step();
                                False otherwise
        
nameargumentsreturns
max_time_stepdiff_rate, delta_xfloat
        Determine a reasonable upper bound on the time step, for the given diffusion rate and delta_x
        This is also based on the "Von Neumann stability analysis"
        (an explanation can be found at: https://www.youtube.com/watch?v=QUiUGNwNNmo)

        This heuristic does NOT take into account the variability of the concentrations across bins
        (such as the magnitude of the 2nd spatial derivative of the concentrations)

        Note: different chemicals with varied diffusion rates will have different max time steps;
              larger diffusion rates call for smaller max steps

        :param diff_rate:   The diffusion rate of the chemical under consideration
        :param delta_x:     The spatial dimension of the bin
        :return:            A relatively safe max length for a single time step of the simulation,
                                to try to steer clear of instabilities
        
nameargumentsreturns
diffuse_step_3_1_stenciltime_step :float, diff :float, conc_array :np.ndarray, permeability=None, delta_x=1np.ndarray
        Note: this is one of alternative methods to do this computation.

        Diffuse the specified single chemical species, for the given small time step, across all bins,
        and set the argument `increment_vector`, containing 1-D array of the changes in concentration ("Delta concentration")
        for the given species across all bins.

        IMPORTANT: the actual system concentrations are NOT changed.

        We're assuming an isolated environment, with nothing diffusing thru the outer "system walls"

        This approach is based on a "3+1 stencil", aka "Explicit Forward-Time Centered Space".
        EXPLANATION:  https://life123.science/diffusion

        Note: the system must contain at least 2 bins, or an error will result.

        :param time_step:   Delta time over which to carry out this single diffusion step;
                                if too large, an Exception will be raised.
        :param diff:        Diffusion rate of the chemical of interest
        :param permeability:Permeability of the chemical of interest
        :param conc_array:  1D Numpy array of concentrations in the bins, for the chemical of interest
        :param delta_x:     Spatial distance between consecutive bins

        :return:            The "increment vector", a 1-D Numpy array with the CHANGE in concentrations
                            across all bins, caused by the diffusion step
        
nameargumentsreturns
diffuse_step_5_1_stenciltime_step: float, diff :float, conc_array, delta_x=1np.ndarray
        Note: this is one of alternative methods to do this computation.

        Similar to diffuse_step_single_species(), but using a "5+1 stencil";
        i.e. spatial derivatives are turned into finite elements using 5 adjacent bins instead of 3.

        For more info, see diffuse_step_single_species()

        IMPORTANT: the actual system concentrations are NOT changed.

        :param time_step:   Delta time over which to carry out this single diffusion step;
                                if too large, an Exception will be raised.
        :param diff:        Diffusion rate of the chemical of interest
        :param conc_array:  1D Numpy array of concentrations in the bins, for the chemical of interest
        :param delta_x:     Spatial distance between consecutive bins

        :return:            The "increment vector", a 1-D Numpy array with the CHANGE in concentrations
                            across all bins, caused by the diffusion step