Пример #1
0
    def _get_cell_times_vmems(self, phase: SimPhase) -> NumpyArrayType:
        '''
        One-dimensional Numpy array of all transmembrane voltages for each
        sampled time step spatially situated at the centre of the single cell
        indexed by the ``plot cell index`` entry specified by the passed
        simulation phase.

        Parameters
        ----------
        phase : SimPhase
            Current simulation phase.
        '''

        # 0-based index of the cell to serialize time data for.
        cell_index = phase.p.visual.single_cell_index

        if phase.p.is_ecm:
            cell_times_vmems = []
            for vm_at_mem in phase.sim.vm_time:
                vm_t = mathunit.upscale_units_milli(
                    cell_ave(phase.cells, vm_at_mem)[cell_index])
                cell_times_vmems.append(vm_t)
        else:
            cell_times_vmems = mathunit.upscale_units_milli(phase.sim.vm_time)

        return nparray.from_iterable(cell_times_vmems)
Пример #2
0
    def voltage_extra(self) -> VectorCellsCache:
        '''
        Vector cache of all upscaled **extracellular voltages** (i.e., voltages
        across all environmental grid spaces) over all sampled time steps of the
        current simulation phase, originally spatially situated at grid space
        centres.

        For readability of units in exported visuals (e.g., plots), voltages are
        cached upscaled from volts (V) to millivolts (mV).
        '''

        # Shape of the extracellular voltages array to be cached. While the
        # original "venv_time" is a two-dimensional array indexed first by
        # sampled time steps and then by flattened grid spaces, this is a
        # three-dimensional array indexed first by sampled time steps and then
        # by nonflattened grid space rows and columns as unique dimensions. Why?
        # Because layers plotting extracellular data assume the latter.
        voltage_extra_shape = (len(
            self._phase.sim.venv_time), ) + self._phase.cells.X.shape

        # Create, return, and create this cache, both upscaled and reshaped as
        # detailed above.
        return VectorCellsCache(
            phase=self._phase,
            times_grids_centre=mathunit.upscale_units_milli(
                self._phase.sim.venv_time).reshape(voltage_extra_shape))
Пример #3
0
    def _plot_frame_figure(self) -> None:

        # Upscaled cell data for the current time step.
        cell_data = mathunit.upscale_units_milli(
            self._cell_time_series[self._time_step])

        #FIXME: Duplicated from above. What we probably want to do is define a
        #new _get_cell_data() method returning this array in a centralized
        #manner callable both here and above. Rays of deluded beaming sunspray!

        # If the unique identifier for the array of cell vertices has *NOT*
        # changed, the cell cluster has *NOT* fundamentally changed and need
        # only be updated with this time step's cell data.
        if self._cell_verts_id == id(self._phase.cells.cell_verts):
            # loggers.log_info(
            #     'Updating animation "{}" cell plots...'.format(self._type))
            self._update_cell_plots(cell_data)
        # Else, the cell cluster has fundamentally changed (e.g., due to
        # physical deformations or cutting events) and must be recreated.
        else:
            # loggers.log_info(
            #     'Reviving animation "{}" cell plots...'.format(self._type))

            # Prevent subsequent calls to this method from erroneously
            # recreating the cell cluster again.
            self._cell_verts_id = id(self._phase.cells.cell_verts)

            # Recreate the cell cluster.
            self._revive_cell_plots(cell_data)

        # Update the color bar with the content of the cell body plot *AFTER*
        # possibly recreating this plot above.
        if self._conf.is_color_autoscaled:
            cell_data_vm = cell_data

            # If autoscaling this colorbar in a telescoping manner and this is
            # *NOT* the first time step, do so.
            #
            # If this is the first time step, the previously calculated minimum
            # and maximum colors are garbage and thus *MUST* be ignored.
            if (self._is_colorbar_autoscaling_telescoped
                    and not self._is_time_step_first):
                self._color_min = min(self._color_min, np.min(cell_data_vm))
                self._color_max = max(self._color_max, np.max(cell_data_vm))
            # Else, autoscale this colorbar in an unrestricted manner.
            else:
                self._color_min = np.min(cell_data_vm)
                self._color_max = np.max(cell_data_vm)

            # Autoscale the colorbar to these colors.
            self._rescale_color_mappables()

        # If displaying this frame...
        if self._is_show:
            # If the current event loop is idle, draw this frame; else, noop.
            # As detailed by the pyplot.draw() docstring, this is the
            # object-oriented equivalent to calling pyplot.draw().
            self._figure.canvas.draw_idle()
Пример #4
0
    def voltage_membrane(self) -> VectorCellsCache:
        '''
        Vector cache of all upscaled **transmembrane voltages** (i.e., voltages
        across all gap junctions connecting intracellular membranes) over all
        sampled time steps of the current simulation phase, originally spatially
        situated at cell membrane midpoints.

        For readability of units in exported visuals (e.g., plots), voltages are
        cached upscaled from volts (V) to millivolts (mV).
        '''

        return VectorCellsCache(
            phase=self._phase,
            times_membranes_midpoint=mathunit.upscale_units_milli(
                self._phase.sim.vm_time))
Пример #5
0
    def export_cells_vmem(self, phase: SimPhase,
                          conf: SimConfExportCSV) -> None:
        '''
        Save one plaintext file in comma-separated value (CSV) format
        containing all transmembrane voltages (Vmem) upscaled and averaged from
        all cell membranes onto cell centres for each sampled time step of the
        current simulation phase.
        '''

        # Two-dimensional Numpy array of all transmembrane voltages.
        cells_times_vmems = mathunit.upscale_units_milli(phase.sim.vm_ave_time)

        # Export this data to this CSV file.
        self._export_cells_times_data(
            phase=phase,
            cells_times_data=cells_times_vmems,
            csv_column_name='Vmem [mV]',
            csv_dir_basename='Vmem2D_TextExport',
            csv_basename_prefix='Vmem2D_',
        )
Пример #6
0
    def export_cell_series(self, phase: SimPhase,
                           conf: SimConfExportCSV) -> None:
        '''
        Save a plaintext file in comma-separated value (CSV) format containing
        several cell-specific time series (e.g., ion concentrations, membrane
        voltages, voltage-gated ion channel pump rates) for the single cell
        indexed ``plot cell index`` in the current simulation configuration.
        '''

        # 0-based index of the cell to serialize time data for.
        cell_index = phase.p.visual.single_cell_index

        # Sequence of key-value pairs containing all simulation data to be
        # exported for this cell, suitable for passing to the
        # OrderedArgsDict.__init__() method calleb below.
        csv_column_name_values = []

        # One-dimensional Numpy array of null data of the required length,
        # suitable for use as CSV column data for columns whose corresponding
        # simulation feature (e.g., deformations) is disabled.
        column_data_empty = np.zeros(len(phase.sim.time))

        # ................{ TIME STEPS                      }..................
        csv_column_name_values.extend(('time_s', phase.sim.time))

        # ................{ VMEM                            }..................
        csv_column_name_values.extend(
            ('Vmem_mV', self._get_cell_times_vmems(phase)))

        # ................{ VMEM ~ goldman                  }..................
        if phase.p.GHK_calc:
            vm_goldman = mathunit.upscale_units_milli([
                vm_GHK_time_cells[cell_index]
                for vm_GHK_time_cells in phase.sim.vm_GHK_time
            ])
        else:
            vm_goldman = column_data_empty

        csv_column_name_values.extend(('Goldman_Vmem_mV', vm_goldman))

        # ................{ Na K PUMP RATE                  }..................
        if phase.p.is_ecm:
            pump_rate = [
                pump_array[phase.cells.cell_to_mems[cell_index][0]]
                for pump_array in phase.sim.rate_NaKATP_time
            ]
        else:
            pump_rate = [
                pump_array[cell_index]
                for pump_array in phase.sim.rate_NaKATP_time
            ]

        csv_column_name_values.extend(('NaK-ATPase_Rate_mol/m2s', pump_rate))

        # ................{ ION CONCENTRATIONS              }..................
        # Create the header starting with cell concentrations.
        for i in range(len(phase.sim.ionlabel)):
            csv_column_name = 'cell_{}_mmol/L'.format(phase.sim.ionlabel[i])
            cc_m = [arr[i][cell_index] for arr in phase.sim.cc_time]
            csv_column_name_values.extend((csv_column_name, cc_m))

        # ................{ MEMBRANE PERMEABILITIES         }..................
        # Create the header starting with membrane permeabilities.
        for i in range(len(phase.sim.ionlabel)):
            if phase.p.is_ecm:
                dd_m = [
                    arr[i][phase.cells.cell_to_mems[cell_index][0]]
                    for arr in phase.sim.dd_time
                ]
            else:
                dd_m = [arr[i][cell_index] for arr in phase.sim.dd_time]

            csv_column_name = 'Dm_{}_m2/s'.format(phase.sim.ionlabel[i])
            csv_column_name_values.extend((csv_column_name, dd_m))

        # ................{ TRANSMEMBRANE CURRENTS          }..................
        if phase.p.is_ecm:
            Imem = [
                memArray[phase.cells.cell_to_mems[cell_index][0]]
                for memArray in phase.sim.I_mem_time
            ]
        else:
            Imem = [memArray[cell_index] for memArray in phase.sim.I_mem_time]

        csv_column_name_values.extend(('I_A/m2', Imem))

        # ................{ HYDROSTATIC PRESSURE            }..................
        p_hydro = [arr[cell_index] for arr in phase.sim.P_cells_time]
        csv_column_name_values.extend(('HydroP_Pa', p_hydro))

        # ................{ OSMOTIC PRESSURE                }..................
        if phase.p.deform_osmo:
            p_osmo = [arr[cell_index] for arr in phase.sim.osmo_P_delta_time]
        else:
            p_osmo = column_data_empty

        csv_column_name_values.extend(('OsmoP_Pa', p_osmo))

        # ................{ DEFORMATION                     }..................
        if (phase.p.deformation and phase.kind is SimPhaseKind.SIM):
            # Extract time-series deformation data for the plot cell:
            dx = nparray.from_iterable(
                [arr[cell_index] for arr in phase.sim.dx_cell_time])
            dy = nparray.from_iterable(
                [arr[cell_index] for arr in phase.sim.dy_cell_time])

            # Get the total magnitude.
            disp = mathunit.upscale_coordinates(np.sqrt(dx**2 + dy**2))
        else:
            disp = column_data_empty

        csv_column_name_values.extend(('Displacement_um', disp))

        # ................{ CSV EXPORT                      }..................
        # Ordered dictionary mapping from CSV column names to data arrays.
        csv_column_name_to_values = OrderedArgsDict(*csv_column_name_values)

        # Export this data to this CSV file.
        npcsv.write_csv(
            filename=self._get_csv_filename(
                phase=phase, basename_sans_filetype='ExportedData'),
            column_name_to_values=csv_column_name_to_values,
        )
Пример #7
0
    def __init__(
            self,

            # Mandatory parameters.
            phase: SimPhase,

            # Optional parameters.

            #FIXME: Permit this option to be configured via a new configuration
            #option in the YAML file.
            #FIXME: Actually, just excise this everywhere. Ally dislikes this
            #effect and I certainly never require it; ergo, remove.
        is_colorbar_autoscaling_telescoped: bool = False,
            *args,
            **kwargs) -> None:
        '''
        Initialize this in-simulation animation.

        Parameters
        ----------
        phase: SimPhase
            Current simulation phase.
        is_colorbar_autoscaling_telescoped : optional[bool]
            ``True`` only if colorbar autoscaling is permitted to increase but
            not decrease the colorbar range *or* ``False`` otherwise (i.e., if
            colorbar autoscaling is permitted to both increase and decrease the
            colorbar range). Such telescoping assists in emphasizing stable
            long-term patterns in cell data at a cost of deemphasizing unstable
            short-term patterns. If colorbar autoscaling is disabled (i.e.,
            ``is_color_autoscaled`` is ``False``), this will be ignored.
            Defaults to ``False``.

        See the superclass method for all remaining parameters.
        '''

        # Initialize the superclass.
        super().__init__(
            *args,

            # Pass this simulation phase as is to our superclass.
            phase=phase,

            # Prevent the superclass from overlaying electric current or
            # concentration flux. Although this class does *NOT* animate a
            # streamplot, the time series required to plot this overlay is
            # unavailable until after the simulation ends.
            is_current_overlayable=False,

            # Save and show this mid-simulation animation only if this
            # configuration has enabled doing so.
            is_save=phase.p.anim.is_while_sim_save,
            is_show=phase.p.anim.is_while_sim_show,

            # Save this mid-simulation animation to a different parent
            # directory than that to which the corresponding post-simulation
            # animation is saved.
            save_dir_parent_basename='anim_while_solving',

            # Pass all remaining arguments as is to our superclass.
            **kwargs)
        # logs.log_debug('Showing mid-simulation animation: {}'.format(self._is_show))

        # Classify all remaining parameters.
        self._is_colorbar_autoscaling_telescoped = (
            is_colorbar_autoscaling_telescoped)

        # Unique identifier for the array of cell vertices. (See docstring.)
        self._cell_verts_id = id(self._phase.cells.cell_verts)

        #FIXME: This is a temp change until we get this right.
        #FIXME: Refactor to call the new
        #Cells.map_membranes_midpoint_to_cells_centre() method instead.

        # Vmem averaged over cell centres.
        vm_o = np.dot(self._phase.cells.M_sum_mems,
                      self._phase.sim.vm) / (self._phase.cells.num_mems)

        # self._cell_time_series = self.sim.vm_time
        self._cell_time_series = self._phase.sim.vm_ave_time

        # cell_data_current = self.sim.vm
        cell_data_current = vm_o

        # Upscaled cell data for the first frame.
        cell_data = mathunit.upscale_units_milli(cell_data_current)

        # Collection of cell polygons with animated voltage data.
        #
        # If *NOT* simulating extracellular spaces, only animate intracellular
        # spaces.
        self._cell_data_plot = self._plot_cells_sans_ecm(cell_data=cell_data)

        # Perform all superclass plotting preparation immediately *BEFORE*
        # plotting this animation's first frame.
        self._prep_figure(
            color_mappables=self._cell_data_plot,
            color_data=cell_data,
        )