dendrotweaks 0.3.1__py3-none-any.whl → 0.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dendrotweaks/__init__.py +2 -2
- dendrotweaks/analysis/ephys_analysis.py +12 -8
- dendrotweaks/biophys/__init__.py +7 -0
- dendrotweaks/{membrane → biophys}/default_templates/NEURON_template.py +5 -3
- dendrotweaks/{membrane → biophys}/default_templates/default.py +2 -1
- dendrotweaks/{membrane → biophys}/default_templates/standard_channel.mod +5 -1
- dendrotweaks/{membrane → biophys}/groups.py +2 -2
- dendrotweaks/biophys/io/__init__.py +11 -0
- dendrotweaks/{membrane → biophys}/io/ast.py +6 -0
- dendrotweaks/{membrane → biophys}/io/code_generators.py +7 -1
- dendrotweaks/{membrane → biophys}/io/converter.py +3 -3
- dendrotweaks/{membrane → biophys}/io/factories.py +8 -6
- dendrotweaks/biophys/io/loader.py +190 -0
- dendrotweaks/{membrane → biophys}/io/parser.py +8 -8
- dendrotweaks/{membrane → biophys}/mechanisms.py +14 -10
- dendrotweaks/model.py +65 -32
- dendrotweaks/morphology/sec_trees.py +1 -1
- dendrotweaks/path_manager.py +9 -11
- dendrotweaks/simulators.py +82 -48
- dendrotweaks/stimuli/populations.py +11 -0
- {dendrotweaks-0.3.1.dist-info → dendrotweaks-0.4.0.dist-info}/METADATA +2 -2
- dendrotweaks-0.4.0.dist-info/RECORD +56 -0
- {dendrotweaks-0.3.1.dist-info → dendrotweaks-0.4.0.dist-info}/WHEEL +1 -1
- dendrotweaks/membrane/__init__.py +0 -6
- dendrotweaks/membrane/io/__init__.py +0 -11
- dendrotweaks/membrane/io/loader.py +0 -90
- dendrotweaks-0.3.1.dist-info/RECORD +0 -56
- /dendrotweaks/{membrane → biophys}/default_mod/AMPA.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/AMPA_NMDA.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/CaDyn.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/GABAa.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/Leak.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/NMDA.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_mod/vecstim.mod +0 -0
- /dendrotweaks/{membrane → biophys}/default_templates/template_jaxley.py +0 -0
- /dendrotweaks/{membrane → biophys}/default_templates/template_jaxley_new.py +0 -0
- /dendrotweaks/{membrane → biophys}/distributions.py +0 -0
- /dendrotweaks/{membrane → biophys}/io/grammar.py +0 -0
- /dendrotweaks/{membrane → biophys}/io/reader.py +0 -0
- {dendrotweaks-0.3.1.dist-info → dendrotweaks-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {dendrotweaks-0.3.1.dist-info → dendrotweaks-0.4.0.dist-info}/top_level.txt +0 -0
    
        dendrotweaks/model.py
    CHANGED
    
    | @@ -9,13 +9,13 @@ from dendrotweaks.morphology.point_trees import PointTree | |
| 9 9 | 
             
            from dendrotweaks.morphology.sec_trees import Section, SectionTree, Domain
         | 
| 10 10 | 
             
            from dendrotweaks.morphology.seg_trees import Segment, SegmentTree
         | 
| 11 11 | 
             
            from dendrotweaks.simulators import NEURONSimulator
         | 
| 12 | 
            -
            from dendrotweaks. | 
| 13 | 
            -
            from dendrotweaks. | 
| 14 | 
            -
            from dendrotweaks. | 
| 15 | 
            -
            from dendrotweaks. | 
| 12 | 
            +
            from dendrotweaks.biophys.groups import SegmentGroup
         | 
| 13 | 
            +
            from dendrotweaks.biophys.mechanisms import Mechanism, LeakChannel, CaDynamics
         | 
| 14 | 
            +
            from dendrotweaks.biophys.io import create_channel, standardize_channel, create_standard_channel
         | 
| 15 | 
            +
            from dendrotweaks.biophys.io import MODFileLoader
         | 
| 16 16 | 
             
            from dendrotweaks.morphology.io import create_point_tree, create_section_tree, create_segment_tree
         | 
| 17 17 | 
             
            from dendrotweaks.stimuli.iclamps import IClamp
         | 
| 18 | 
            -
            from dendrotweaks. | 
| 18 | 
            +
            from dendrotweaks.biophys.distributions import Distribution
         | 
| 19 19 | 
             
            from dendrotweaks.stimuli.populations import Population
         | 
| 20 20 | 
             
            from dendrotweaks.utils import calculate_lambda_f, dynamic_import
         | 
| 21 21 | 
             
            from dendrotweaks.utils import get_domain_color, timeit
         | 
| @@ -343,11 +343,11 @@ class Model(): | |
| 343 343 | 
             
                    """
         | 
| 344 344 | 
             
                    return self.path_manager.list_files('morphology', extension=extension)
         | 
| 345 345 |  | 
| 346 | 
            -
                def  | 
| 346 | 
            +
                def list_biophys(self, extension='json'):
         | 
| 347 347 | 
             
                    """
         | 
| 348 | 
            -
                    List the  | 
| 348 | 
            +
                    List the biophysical configurations available for the model.
         | 
| 349 349 | 
             
                    """
         | 
| 350 | 
            -
                    return self.path_manager.list_files(' | 
| 350 | 
            +
                    return self.path_manager.list_files('biophys', extension=extension)
         | 
| 351 351 |  | 
| 352 352 | 
             
                def list_mechanisms(self, extension='mod'):
         | 
| 353 353 | 
             
                    """
         | 
| @@ -355,7 +355,7 @@ class Model(): | |
| 355 355 | 
             
                    """
         | 
| 356 356 | 
             
                    return self.path_manager.list_files('mod', extension=extension)
         | 
| 357 357 |  | 
| 358 | 
            -
                def  | 
| 358 | 
            +
                def list_stimuli(self, extension='json'):
         | 
| 359 359 | 
             
                    """
         | 
| 360 360 | 
             
                    List the stimuli configurations available for the model.
         | 
| 361 361 | 
             
                    """
         | 
| @@ -1287,7 +1287,7 @@ class Model(): | |
| 1287 1287 | 
             
                    print(f'Recording added to sec {sec} at loc {loc}.')
         | 
| 1288 1288 |  | 
| 1289 1289 |  | 
| 1290 | 
            -
                def remove_recording(self, sec, loc):
         | 
| 1290 | 
            +
                def remove_recording(self, sec, loc, var='v'):
         | 
| 1291 1291 | 
             
                    """
         | 
| 1292 1292 | 
             
                    Remove a recording from the model.
         | 
| 1293 1293 |  | 
| @@ -1298,14 +1298,14 @@ class Model(): | |
| 1298 1298 | 
             
                    loc : float
         | 
| 1299 1299 | 
             
                        The location along the normalized section length to remove the recording from.
         | 
| 1300 1300 | 
             
                    """
         | 
| 1301 | 
            -
                    self.simulator.remove_recording(sec, loc)
         | 
| 1301 | 
            +
                    self.simulator.remove_recording(sec, loc, var)
         | 
| 1302 1302 |  | 
| 1303 1303 |  | 
| 1304 | 
            -
                def remove_all_recordings(self):
         | 
| 1304 | 
            +
                def remove_all_recordings(self, var=None):
         | 
| 1305 1305 | 
             
                    """
         | 
| 1306 1306 | 
             
                    Remove all recordings from the model.
         | 
| 1307 1307 | 
             
                    """
         | 
| 1308 | 
            -
                    self.simulator.remove_all_recordings()
         | 
| 1308 | 
            +
                    self.simulator.remove_all_recordings(var=var)
         | 
| 1309 1309 |  | 
| 1310 1310 |  | 
| 1311 1311 | 
             
                def run(self, duration=300):
         | 
| @@ -1598,7 +1598,7 @@ class Model(): | |
| 1598 1598 | 
             
                        'name': self.name,
         | 
| 1599 1599 | 
             
                        },
         | 
| 1600 1600 | 
             
                        'd_lambda': self.d_lambda,
         | 
| 1601 | 
            -
                        'domains': {domain: list(mechs) for domain, mechs in self.domains_to_mechs.items()},
         | 
| 1601 | 
            +
                        'domains': {domain: sorted(list(mechs)) for domain, mechs in self.domains_to_mechs.items()},
         | 
| 1602 1602 | 
             
                        'groups': [
         | 
| 1603 1603 | 
             
                        group.to_dict() for group in self._groups
         | 
| 1604 1604 | 
             
                        ],
         | 
| @@ -1657,9 +1657,9 @@ class Model(): | |
| 1657 1657 |  | 
| 1658 1658 |  | 
| 1659 1659 |  | 
| 1660 | 
            -
                def  | 
| 1660 | 
            +
                def export_biophys(self, file_name, **kwargs):
         | 
| 1661 1661 | 
             
                    """
         | 
| 1662 | 
            -
                    Export the  | 
| 1662 | 
            +
                    Export the biophysical properties of the model to a JSON file.
         | 
| 1663 1663 |  | 
| 1664 1664 | 
             
                    Parameters
         | 
| 1665 1665 | 
             
                    ----------
         | 
| @@ -1669,16 +1669,18 @@ class Model(): | |
| 1669 1669 | 
             
                        Additional keyword arguments to pass to `json.dump`.
         | 
| 1670 1670 | 
             
                    """        
         | 
| 1671 1671 |  | 
| 1672 | 
            -
                    path_to_json = self.path_manager.get_file_path(' | 
| 1672 | 
            +
                    path_to_json = self.path_manager.get_file_path('biophys', file_name, extension='json')
         | 
| 1673 | 
            +
                    if not kwargs.get('indent'):
         | 
| 1674 | 
            +
                        kwargs['indent'] = 4
         | 
| 1673 1675 |  | 
| 1674 1676 | 
             
                    data = self.to_dict()
         | 
| 1675 1677 | 
             
                    with open(path_to_json, 'w') as f:
         | 
| 1676 1678 | 
             
                        json.dump(data, f, **kwargs)
         | 
| 1677 1679 |  | 
| 1678 1680 |  | 
| 1679 | 
            -
                def  | 
| 1681 | 
            +
                def load_biophys(self, file_name, recompile=True):
         | 
| 1680 1682 | 
             
                    """
         | 
| 1681 | 
            -
                    Load the  | 
| 1683 | 
            +
                    Load the biophysical properties of the model from a JSON file.
         | 
| 1682 1684 |  | 
| 1683 1685 | 
             
                    Parameters
         | 
| 1684 1686 | 
             
                    ----------
         | 
| @@ -1688,13 +1690,18 @@ class Model(): | |
| 1688 1690 | 
             
                        Whether to recompile the mechanisms after loading. Default is True.
         | 
| 1689 1691 | 
             
                    """
         | 
| 1690 1692 | 
             
                    self.add_default_mechanisms()
         | 
| 1691 | 
            -
                     | 
| 1693 | 
            +
                    
         | 
| 1692 1694 |  | 
| 1693 | 
            -
                    path_to_json = self.path_manager.get_file_path(' | 
| 1695 | 
            +
                    path_to_json = self.path_manager.get_file_path('biophys', file_name, extension='json')
         | 
| 1694 1696 |  | 
| 1695 1697 | 
             
                    with open(path_to_json, 'r') as f:
         | 
| 1696 1698 | 
             
                        data = json.load(f)
         | 
| 1697 1699 |  | 
| 1700 | 
            +
                    for mech_name in {mech for mechs in data['domains'].values() for mech in mechs}:
         | 
| 1701 | 
            +
                        if mech_name in ['Leak', 'CaDyn', 'Independent']:
         | 
| 1702 | 
            +
                            continue
         | 
| 1703 | 
            +
                        self.add_mechanism(mech_name, dir_name='mod', recompile=recompile)            
         | 
| 1704 | 
            +
             | 
| 1698 1705 | 
             
                    self.from_dict(data)
         | 
| 1699 1706 |  | 
| 1700 1707 |  | 
| @@ -1715,6 +1722,14 @@ class Model(): | |
| 1715 1722 | 
             
                            **self.simulator.to_dict(),
         | 
| 1716 1723 | 
             
                        },
         | 
| 1717 1724 | 
             
                        'stimuli': {
         | 
| 1725 | 
            +
                            'recordings': [
         | 
| 1726 | 
            +
                                {
         | 
| 1727 | 
            +
                                    'name': f'rec_{i}',
         | 
| 1728 | 
            +
                                    'var': var
         | 
| 1729 | 
            +
                                } 
         | 
| 1730 | 
            +
                                for var, recs in self.simulator.recordings.items()
         | 
| 1731 | 
            +
                                for i, _ in enumerate(recs)
         | 
| 1732 | 
            +
                            ],
         | 
| 1718 1733 | 
             
                            'iclamps': [
         | 
| 1719 1734 | 
             
                                {
         | 
| 1720 1735 | 
             
                                    'name': f'iclamp_{i}',
         | 
| @@ -1743,11 +1758,16 @@ class Model(): | |
| 1743 1758 | 
             
                    """
         | 
| 1744 1759 |  | 
| 1745 1760 | 
             
                    rec_data = {
         | 
| 1746 | 
            -
                        'type': [ | 
| 1747 | 
            -
                        'idx': [ | 
| 1748 | 
            -
                        'sec_idx': [ | 
| 1749 | 
            -
                        'loc': [ | 
| 1761 | 
            +
                        'type': [],
         | 
| 1762 | 
            +
                        'idx': [],
         | 
| 1763 | 
            +
                        'sec_idx': [],
         | 
| 1764 | 
            +
                        'loc': [],
         | 
| 1750 1765 | 
             
                    }
         | 
| 1766 | 
            +
                    for var, recs in self.simulator.recordings.items():
         | 
| 1767 | 
            +
                        rec_data['type'].extend(['rec'] * len(recs))
         | 
| 1768 | 
            +
                        rec_data['idx'].extend([i for i in range(len(recs))])
         | 
| 1769 | 
            +
                        rec_data['sec_idx'].extend([seg._section.idx for seg in recs])
         | 
| 1770 | 
            +
                        rec_data['loc'].extend([seg.x for seg in recs])
         | 
| 1751 1771 |  | 
| 1752 1772 | 
             
                    iclamp_data = {
         | 
| 1753 1773 | 
             
                        'type': ['iclamp'] * len(self.iclamps),
         | 
| @@ -1776,6 +1796,7 @@ class Model(): | |
| 1776 1796 | 
             
                        pd.DataFrame(iclamp_data),
         | 
| 1777 1797 | 
             
                        pd.DataFrame(synapses_data)
         | 
| 1778 1798 | 
             
                    ], ignore_index=True)
         | 
| 1799 | 
            +
                    df['idx'] = df['idx'].astype(int)
         | 
| 1779 1800 | 
             
                    df['sec_idx'] = df['sec_idx'].astype(int)
         | 
| 1780 1801 | 
             
                    if path_to_csv: df.to_csv(path_to_csv, index=False)
         | 
| 1781 1802 |  | 
| @@ -1797,6 +1818,8 @@ class Model(): | |
| 1797 1818 |  | 
| 1798 1819 | 
             
                    data = self.stimuli_to_dict()
         | 
| 1799 1820 |  | 
| 1821 | 
            +
                    if not kwargs.get('indent'):
         | 
| 1822 | 
            +
                        kwargs['indent'] = 4
         | 
| 1800 1823 | 
             
                    with open(path_to_json, 'w') as f:
         | 
| 1801 1824 | 
             
                        json.dump(data, f, **kwargs)
         | 
| 1802 1825 |  | 
| @@ -1827,13 +1850,9 @@ class Model(): | |
| 1827 1850 |  | 
| 1828 1851 | 
             
                    self.simulator.from_dict(data['simulation'])
         | 
| 1829 1852 |  | 
| 1830 | 
            -
                    #  | 
| 1831 | 
            -
             | 
| 1832 | 
            -
                     | 
| 1833 | 
            -
                    for i, row in df_recs.iterrows():
         | 
| 1834 | 
            -
                        self.add_recording(
         | 
| 1835 | 
            -
                            self.sec_tree.sections[row['sec_idx']], row['loc']
         | 
| 1836 | 
            -
                        )
         | 
| 1853 | 
            +
                    # Clear all stimuli and recordings
         | 
| 1854 | 
            +
                    self.remove_all_stimuli()
         | 
| 1855 | 
            +
                    self.remove_all_recordings()
         | 
| 1837 1856 |  | 
| 1838 1857 | 
             
                    # IClamps -----------------------------------------------------------
         | 
| 1839 1858 |  | 
| @@ -1875,6 +1894,20 @@ class Model(): | |
| 1875 1894 | 
             
                            pop.update_input_params(**pop_data['input_params'])
         | 
| 1876 1895 | 
             
                            self._add_population(pop)
         | 
| 1877 1896 |  | 
| 1897 | 
            +
                    # Recordings ---------------------------------------------------------
         | 
| 1898 | 
            +
             | 
| 1899 | 
            +
                    df_recs = df_stimuli[df_stimuli['type'] == 'rec'].reset_index(drop=True, inplace=False)
         | 
| 1900 | 
            +
                    for i, row in df_recs.iterrows():
         | 
| 1901 | 
            +
                        # TODO: This conditional statement is to account for a recent change
         | 
| 1902 | 
            +
                        # in the JSON structure. It should be removed in the future.
         | 
| 1903 | 
            +
                        if data['stimuli'].get('recordings'):
         | 
| 1904 | 
            +
                            var = data['stimuli']['recordings'][i]['var']
         | 
| 1905 | 
            +
                        else:
         | 
| 1906 | 
            +
                            var = 'v'
         | 
| 1907 | 
            +
                        self.add_recording(
         | 
| 1908 | 
            +
                            self.sec_tree.sections[row['sec_idx']], row['loc'], var
         | 
| 1909 | 
            +
                        )
         | 
| 1910 | 
            +
             | 
| 1878 1911 |  | 
| 1879 1912 | 
             
                def export_to_NEURON(self, file_name, include_kinetic_params=True):
         | 
| 1880 1913 | 
             
                    """
         | 
| @@ -770,7 +770,7 @@ class SectionTree(Tree): | |
| 770 770 | 
             
                    """
         | 
| 771 771 |  | 
| 772 772 | 
             
                    unique_domain_names = set([sec.domain for sec in self.sections])
         | 
| 773 | 
            -
                    self.domains = {name: Domain(name) for name in unique_domain_names}
         | 
| 773 | 
            +
                    self.domains = {name: Domain(name) for name in sorted(unique_domain_names)}
         | 
| 774 774 |  | 
| 775 775 | 
             
                    for sec in self.sections:
         | 
| 776 776 | 
             
                        self.domains[sec.domain].add_section(sec)
         | 
    
        dendrotweaks/path_manager.py
    CHANGED
    
    | @@ -26,9 +26,9 @@ class PathManager: | |
| 26 26 | 
             
                        'default_mod': os.path.join(self.path_to_data, 'Default'),
         | 
| 27 27 | 
             
                        'templates': os.path.join(self.path_to_data, 'Templates'),
         | 
| 28 28 | 
             
                        'morphology': os.path.join(self.path_to_model, 'morphology'),
         | 
| 29 | 
            -
                        ' | 
| 30 | 
            -
                        'mod': os.path.join(self.path_to_model, ' | 
| 31 | 
            -
                        'python': os.path.join(self.path_to_model, ' | 
| 29 | 
            +
                        'biophys': os.path.join(self.path_to_model, 'biophys'),
         | 
| 30 | 
            +
                        'mod': os.path.join(self.path_to_model, 'biophys', 'mod'),
         | 
| 31 | 
            +
                        'python': os.path.join(self.path_to_model, 'biophys', 'python'),
         | 
| 32 32 | 
             
                        'stimuli': os.path.join(self.path_to_model, 'stimuli'),
         | 
| 33 33 | 
             
                    }
         | 
| 34 34 | 
             
                    self._ensure_paths_exist()
         | 
| @@ -61,8 +61,7 @@ class PathManager: | |
| 61 61 | 
             
                    """
         | 
| 62 62 | 
             
                    Copy default mod files to the data directory.
         | 
| 63 63 | 
             
                    """
         | 
| 64 | 
            -
                     | 
| 65 | 
            -
                    DEFAULT_MOD_DIR = os.path.join(os.path.dirname(__file__), 'membrane', 'default_mod')
         | 
| 64 | 
            +
                    DEFAULT_MOD_DIR = os.path.join(os.path.dirname(__file__), 'biophys', 'default_mod')
         | 
| 66 65 | 
             
                    for file_name in os.listdir(DEFAULT_MOD_DIR):
         | 
| 67 66 | 
             
                        source = os.path.join(DEFAULT_MOD_DIR, file_name)
         | 
| 68 67 | 
             
                        destination = os.path.join(self.paths['default_mod'], file_name)
         | 
| @@ -72,8 +71,7 @@ class PathManager: | |
| 72 71 | 
             
                    """
         | 
| 73 72 | 
             
                    Copy template files to the data directory.
         | 
| 74 73 | 
             
                    """
         | 
| 75 | 
            -
                     | 
| 76 | 
            -
                    TEMPLATES_DIR = os.path.join(os.path.dirname(__file__), 'membrane', 'default_templates')
         | 
| 74 | 
            +
                    TEMPLATES_DIR = os.path.join(os.path.dirname(__file__), 'biophys', 'default_templates')
         | 
| 77 75 | 
             
                    for file_name in os.listdir(TEMPLATES_DIR):
         | 
| 78 76 | 
             
                        source = os.path.join(TEMPLATES_DIR, file_name)
         | 
| 79 77 | 
             
                        destination = os.path.join(self.paths['templates'], file_name)
         | 
| @@ -169,16 +167,16 @@ class PathManager: | |
| 169 167 | 
             
                    return self.list_files('stimuli', extension=extension)
         | 
| 170 168 |  | 
| 171 169 |  | 
| 172 | 
            -
                def  | 
| 170 | 
            +
                def list_biophys(self):
         | 
| 173 171 | 
             
                    """
         | 
| 174 | 
            -
                    List all  | 
| 172 | 
            +
                    List all biophysics files.
         | 
| 175 173 |  | 
| 176 174 | 
             
                    Returns
         | 
| 177 175 | 
             
                    -------
         | 
| 178 176 | 
             
                    List[str]
         | 
| 179 | 
            -
                        A list of  | 
| 177 | 
            +
                        A list of biophysics file names.
         | 
| 180 178 | 
             
                    """
         | 
| 181 | 
            -
                    return self.list_files(' | 
| 179 | 
            +
                    return self.list_files('biophys', extension='.json')
         | 
| 182 180 |  | 
| 183 181 |  | 
| 184 182 | 
             
                def print_directory_tree(self, subfolder=None) -> None:
         | 
    
        dendrotweaks/simulators.py
    CHANGED
    
    | @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            from collections import defaultdict
         | 
| 2 2 | 
             
            import warnings
         | 
| 3 | 
            +
            from functools import cached_property
         | 
| 3 4 |  | 
| 4 5 | 
             
            import matplotlib.pyplot as plt
         | 
| 5 6 | 
             
            import neuron
         | 
| @@ -35,26 +36,47 @@ class Simulator: | |
| 35 36 | 
             
                A generic simulator class.
         | 
| 36 37 | 
             
                """
         | 
| 37 38 | 
             
                def __init__(self):
         | 
| 38 | 
            -
                    self. | 
| 39 | 
            -
                    self.t = None
         | 
| 39 | 
            +
                    self._t = None
         | 
| 40 40 | 
             
                    self.dt = None
         | 
| 41 | 
            -
                    self. | 
| 41 | 
            +
                    self._recordings = {'v': {}}
         | 
| 42 42 |  | 
| 43 | 
            -
                def  | 
| 43 | 
            +
                def plot_var(self, var='v', ax=None, segments=None, **kwargs):
         | 
| 44 | 
            +
                    if self._t is None:
         | 
| 45 | 
            +
                        raise ValueError('Simulation has not been run yet.')
         | 
| 46 | 
            +
                    if var not in self.recordings:
         | 
| 47 | 
            +
                        raise ValueError(f'Variable {var} not recorded.')
         | 
| 44 48 | 
             
                    if ax is None:
         | 
| 45 49 | 
             
                        fig, ax = plt.subplots()
         | 
| 46 50 | 
             
                    if segments is None:
         | 
| 47 | 
            -
                        segments = self.recordings.keys()
         | 
| 48 | 
            -
                    for seg,  | 
| 51 | 
            +
                        segments = self.recordings[var].keys()
         | 
| 52 | 
            +
                    for seg, x in self.recordings[var].items():
         | 
| 49 53 | 
             
                        if segments and seg not in segments:
         | 
| 50 54 | 
             
                            continue
         | 
| 51 | 
            -
                        ax.plot(self.t,  | 
| 52 | 
            -
             | 
| 55 | 
            +
                        ax.plot(self.t, x, label=f'{var} {seg.domain} {seg.idx}', **kwargs)
         | 
| 53 56 | 
             
                    if len(segments) < 10:
         | 
| 54 57 | 
             
                        ax.legend()
         | 
| 55 | 
            -
                    # ax.set_ylim(-100, 60)
         | 
| 56 58 | 
             
                    ax.set_xlabel('Time (ms)')
         | 
| 57 | 
            -
                     | 
| 59 | 
            +
                    if var == 'v':
         | 
| 60 | 
            +
                        ax.set_ylabel('Voltage (mV)')
         | 
| 61 | 
            +
                    elif var.startswith('i_'):
         | 
| 62 | 
            +
                        ax.set_ylabel('Current (nA)')
         | 
| 63 | 
            +
                    return ax
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def plot_voltage(self, **kwargs):
         | 
| 66 | 
            +
                    """
         | 
| 67 | 
            +
                    Plot the recorded voltages.
         | 
| 68 | 
            +
                    """
         | 
| 69 | 
            +
                    self.plot_var('v', **kwargs)
         | 
| 70 | 
            +
                
         | 
| 71 | 
            +
                def plot_currents(self, **kwargs):
         | 
| 72 | 
            +
                    """
         | 
| 73 | 
            +
                    Plot the recorded currents.
         | 
| 74 | 
            +
                    """
         | 
| 75 | 
            +
                    ax = kwargs.pop('ax', None)
         | 
| 76 | 
            +
                    for var in self.recordings:
         | 
| 77 | 
            +
                        if var.startswith('i_'):
         | 
| 78 | 
            +
                            ax = self.plot_var(var, ax=ax, **kwargs)
         | 
| 79 | 
            +
                        
         | 
| 58 80 |  | 
| 59 81 |  | 
| 60 82 | 
             
            class NEURONSimulator(Simulator):
         | 
| @@ -88,10 +110,33 @@ class NEURONSimulator(Simulator): | |
| 88 110 | 
             
                    self.temperature = temperature
         | 
| 89 111 | 
             
                    self.v_init = v_init * mV
         | 
| 90 112 | 
             
                    self._duration = 300
         | 
| 113 | 
            +
                    
         | 
| 91 114 |  | 
| 92 115 | 
             
                    self.dt = dt
         | 
| 93 116 | 
             
                    self._cvode = cvode
         | 
| 94 117 |  | 
| 118 | 
            +
                @cached_property
         | 
| 119 | 
            +
                def recordings(self):
         | 
| 120 | 
            +
                    return {
         | 
| 121 | 
            +
                        var:{ seg: vec.to_python() for seg, vec in recs.items() }
         | 
| 122 | 
            +
                        for var, recs in self._recordings.items()
         | 
| 123 | 
            +
                    }
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                @cached_property
         | 
| 126 | 
            +
                def t(self):
         | 
| 127 | 
            +
                    return self._t.to_python()
         | 
| 128 | 
            +
             | 
| 129 | 
            +
                def _clean_cache(self):
         | 
| 130 | 
            +
                    """
         | 
| 131 | 
            +
                    Clean the cache of the simulator.
         | 
| 132 | 
            +
                    """
         | 
| 133 | 
            +
                    try:
         | 
| 134 | 
            +
                        del self.recordings
         | 
| 135 | 
            +
                        del self.t
         | 
| 136 | 
            +
                    except AttributeError:
         | 
| 137 | 
            +
                        # Property hasn't been accessed yet, so no need to delete
         | 
| 138 | 
            +
                        pass
         | 
| 139 | 
            +
             | 
| 95 140 |  | 
| 96 141 | 
             
                def add_recording(self, sec, loc, var='v'):
         | 
| 97 142 | 
             
                    """
         | 
| @@ -107,11 +152,16 @@ class NEURONSimulator(Simulator): | |
| 107 152 | 
             
                        The variable to record. Default is 'v' (voltage).
         | 
| 108 153 | 
             
                    """
         | 
| 109 154 | 
             
                    seg = sec(loc)
         | 
| 110 | 
            -
                    if  | 
| 111 | 
            -
                         | 
| 112 | 
            -
                    self. | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 155 | 
            +
                    if not hasattr(seg._ref, f'_ref_{var}'):
         | 
| 156 | 
            +
                        raise ValueError(f'Segment {seg} does not have variable {var}.')
         | 
| 157 | 
            +
                    if self._recordings.get(var, {}).get(seg):
         | 
| 158 | 
            +
                        self.remove_recording(sec, loc, var)
         | 
| 159 | 
            +
                    if var not in self._recordings:
         | 
| 160 | 
            +
                        self._recordings[var] = {}
         | 
| 161 | 
            +
                    self._recordings[var][seg] = h.Vector().record(getattr(seg._ref, f'_ref_{var}'))
         | 
| 162 | 
            +
                    self._clean_cache()
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                def remove_recording(self, sec, loc, var='v'):
         | 
| 115 165 | 
             
                    """
         | 
| 116 166 | 
             
                    Remove a recording from the simulator.
         | 
| 117 167 |  | 
| @@ -123,20 +173,23 @@ class NEURONSimulator(Simulator): | |
| 123 173 | 
             
                        The location along the normalized section length to remove the recording from.
         | 
| 124 174 | 
             
                    """
         | 
| 125 175 | 
             
                    seg = sec(loc)
         | 
| 126 | 
            -
                    if self. | 
| 127 | 
            -
                        self. | 
| 128 | 
            -
                        self. | 
| 129 | 
            -
             | 
| 130 | 
            -
             | 
| 176 | 
            +
                    if self._recordings[var].get(seg):
         | 
| 177 | 
            +
                        self._recordings[var][seg] = None
         | 
| 178 | 
            +
                        self._recordings[var].pop(seg)
         | 
| 179 | 
            +
                        if not self._recordings[var]:
         | 
| 180 | 
            +
                            self._recordings.pop(var)
         | 
| 181 | 
            +
                    self._clean_cache()
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                def remove_all_recordings(self, var=None):
         | 
| 131 184 | 
             
                    """
         | 
| 132 185 | 
             
                    Remove all recordings from the simulator.
         | 
| 133 186 | 
             
                    """
         | 
| 134 | 
            -
                     | 
| 135 | 
            -
             | 
| 136 | 
            -
                        self. | 
| 137 | 
            -
             | 
| 138 | 
            -
                         | 
| 139 | 
            -
             | 
| 187 | 
            +
                    variables = [var] if var else list(self._recordings.keys())
         | 
| 188 | 
            +
                    for variable in variables:
         | 
| 189 | 
            +
                        for seg in list(self._recordings.get(variable, {}).keys()):
         | 
| 190 | 
            +
                            self.remove_recording(seg._section, seg.x, variable)
         | 
| 191 | 
            +
                        if self._recordings.get(variable):
         | 
| 192 | 
            +
                            warnings.warn(f'Not all recordings were removed for variable {variable}: {self._recordings}')
         | 
| 140 193 |  | 
| 141 194 |  | 
| 142 195 | 
             
                def _init_simulation(self):
         | 
| @@ -161,35 +214,16 @@ class NEURONSimulator(Simulator): | |
| 161 214 | 
             
                    duration : float
         | 
| 162 215 | 
             
                        The duration of the simulation in milliseconds.
         | 
| 163 216 | 
             
                    """
         | 
| 164 | 
            -
                    self._duration = duration
         | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
                    # vs = list(self.recordings.values())
         | 
| 168 | 
            -
                    Is = []
         | 
| 169 217 |  | 
| 170 | 
            -
                     | 
| 171 | 
            -
                    #     # v = h.Vector().record(seg._ref_v)
         | 
| 172 | 
            -
                    #     vs.append(v)
         | 
| 218 | 
            +
                    self._clean_cache()
         | 
| 173 219 |  | 
| 174 | 
            -
                     | 
| 220 | 
            +
                    self._duration = duration
         | 
| 175 221 |  | 
| 176 | 
            -
                     | 
| 177 | 
            -
                    #     pass
         | 
| 178 | 
            -
                    # else:
         | 
| 179 | 
            -
                    #     for seg in self.recordings.keys():
         | 
| 180 | 
            -
                    #         if getattr(seg, f'_ref_i_{self.ch.suffix}', None) is None:
         | 
| 181 | 
            -
                    #             logger.warning(
         | 
| 182 | 
            -
                    #                 f'No current recorded for {self.ch.suffix} at {seg}. Make i a RANGE variable in mod file.')
         | 
| 183 | 
            -
                    #             continue
         | 
| 184 | 
            -
                    #         I = h.Vector().record(getattr(seg, f'_ref_i_{self.ch.suffix}'))
         | 
| 185 | 
            -
                    #         Is.append(I)
         | 
| 222 | 
            +
                    self._t = h.Vector().record(h._ref_t)
         | 
| 186 223 |  | 
| 187 224 | 
             
                    self._init_simulation()
         | 
| 188 225 |  | 
| 189 226 | 
             
                    h.continuerun(duration * ms)
         | 
| 190 | 
            -
             | 
| 191 | 
            -
                    self.t = t.to_python()
         | 
| 192 | 
            -
                    self.vs = {seg: v.to_python() for seg, v in self.recordings.items()}
         | 
| 193 227 |  | 
| 194 228 |  | 
| 195 229 | 
             
                def to_dict(self):
         | 
| @@ -123,6 +123,17 @@ class Population(): | |
| 123 123 | 
             
                            spike_times[syn].extend(syn.spike_times)
         | 
| 124 124 | 
             
                    return dict(spike_times)
         | 
| 125 125 |  | 
| 126 | 
            +
                @property
         | 
| 127 | 
            +
                def n_per_seg(self):
         | 
| 128 | 
            +
                    """
         | 
| 129 | 
            +
                    Return the number of synapses per segment.
         | 
| 130 | 
            +
                    """
         | 
| 131 | 
            +
                    n_per_seg = {seg: 0 for seg in self.segments}
         | 
| 132 | 
            +
                    for (sec, loc), syns in self.synapses.items():
         | 
| 133 | 
            +
                        seg = sec(loc)
         | 
| 134 | 
            +
                        n_per_seg[seg] += len(syns)
         | 
| 135 | 
            +
                    return dict(n_per_seg)
         | 
| 136 | 
            +
                        
         | 
| 126 137 |  | 
| 127 138 | 
             
                def update_kinetic_params(self, **params):
         | 
| 128 139 | 
             
                    """
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Metadata-Version: 2.4
         | 
| 2 2 | 
             
            Name: dendrotweaks
         | 
| 3 | 
            -
            Version: 0. | 
| 3 | 
            +
            Version: 0.4.0
         | 
| 4 4 | 
             
            Summary: A toolbox for exploring dendritic dynamics
         | 
| 5 5 | 
             
            Home-page: https://dendrotweaks.dendrites.gr
         | 
| 6 6 | 
             
            Author: Roman Makarov
         | 
| @@ -15,7 +15,7 @@ Classifier: Operating System :: OS Independent | |
| 15 15 | 
             
            Requires-Python: >=3.9
         | 
| 16 16 | 
             
            Description-Content-Type: text/markdown
         | 
| 17 17 | 
             
            License-File: LICENSE
         | 
| 18 | 
            -
            Requires-Dist: neuron>=8.2.6
         | 
| 18 | 
            +
            Requires-Dist: neuron>=8.2.6; sys_platform == "linux" or sys_platform == "darwin"
         | 
| 19 19 | 
             
            Requires-Dist: neuron-reduce==0.0.7
         | 
| 20 20 | 
             
            Requires-Dist: numpy<2.0.0
         | 
| 21 21 | 
             
            Requires-Dist: pandas
         | 
| @@ -0,0 +1,56 @@ | |
| 1 | 
            +
            dendrotweaks/__init__.py,sha256=qmlQDMHQGSD70naZme_cEMgale9T5OH6VqjdxhznouM,384
         | 
| 2 | 
            +
            dendrotweaks/model.py,sha256=XX4WPaHPYUzm9CF4S6lUCDc_a1mORJaEbwtLexqEKCQ,68796
         | 
| 3 | 
            +
            dendrotweaks/model_io.py,sha256=xwXKMcUle-Y0HoWFYVZu3G8v4pdQXmeaDfl2Xi65eHw,2137
         | 
| 4 | 
            +
            dendrotweaks/path_manager.py,sha256=dai5o6UA0nk-ubwKWRu4LFdDBO77zW_SsMf6k0MLBiI,8703
         | 
| 5 | 
            +
            dendrotweaks/simulators.py,sha256=ADiXPqcWZ7oLQfMMnhgQNpgCW-NE6lBb5hZCQACSIkM,7237
         | 
| 6 | 
            +
            dendrotweaks/utils.py,sha256=jaUJNb39Bsevg3WJByP56bO7CLj1wzlh-uGZl-lxi1I,7131
         | 
| 7 | 
            +
            dendrotweaks/analysis/__init__.py,sha256=SEYpoQ5iXiQXyHB20-IAdDHYI-7CR5GYFXIwr-O05Ug,858
         | 
| 8 | 
            +
            dendrotweaks/analysis/ephys_analysis.py,sha256=Caiww27p9dnL5_27OmZ95AZ_OmefvImAPyItsJMSdmA,14320
         | 
| 9 | 
            +
            dendrotweaks/analysis/morphometric_analysis.py,sha256=5zohjGssyx-wezI-yY3Q-kYM_wzAQLLFBJ9Xk950_JY,3571
         | 
| 10 | 
            +
            dendrotweaks/biophys/__init__.py,sha256=k0o2xwyoaJUb1lfO9OHtqxheNP6R-Ya5o0g-bJOdCZg,360
         | 
| 11 | 
            +
            dendrotweaks/biophys/distributions.py,sha256=ADPFPA-CN7AbRJj0Ry4TxFZJhdYXJm87iIGWZSDr5vI,10299
         | 
| 12 | 
            +
            dendrotweaks/biophys/groups.py,sha256=Kze8ft8EYFXWW6zJhhbpWQUUt82L47g2IbB-5WpsWrY,3481
         | 
| 13 | 
            +
            dendrotweaks/biophys/mechanisms.py,sha256=j9uygcwkK6Z_08hpTHax40Wn-eV4V_k_on_KyPDnO90,18520
         | 
| 14 | 
            +
            dendrotweaks/biophys/default_mod/AMPA.mod,sha256=HY_pWzYvaSDV-w7qruenG2mnll8v79s40HFHjUCIi4U,980
         | 
| 15 | 
            +
            dendrotweaks/biophys/default_mod/AMPA_NMDA.mod,sha256=ztv2ePUiEQZ93-23FTkGO2DC91rehQuqo0NUIbHZ368,2318
         | 
| 16 | 
            +
            dendrotweaks/biophys/default_mod/CaDyn.mod,sha256=gwc69K_rxu2w_mV7CnOSOnVaCMc8Z-MfdBFf6lAj4kg,1298
         | 
| 17 | 
            +
            dendrotweaks/biophys/default_mod/GABAa.mod,sha256=jdGRid-Wzw4y9kHvq74oSMogLhSiS-Ac2DDaLOrxVi8,983
         | 
| 18 | 
            +
            dendrotweaks/biophys/default_mod/Leak.mod,sha256=u0lwMYGgl5kNZN5W4N6YHgRSeVxb-z2oM9fqou5rCV8,420
         | 
| 19 | 
            +
            dendrotweaks/biophys/default_mod/NMDA.mod,sha256=tT4Q5UPoeztXcQ45uZc2PUO3-8OkDLCmrS7WDsn1yQQ,1185
         | 
| 20 | 
            +
            dendrotweaks/biophys/default_mod/vecstim.mod,sha256=iSpJgR96O2Z3pLNUFIsZ7YJ529ncKUBaZqDJvA0_oV0,965
         | 
| 21 | 
            +
            dendrotweaks/biophys/default_templates/NEURON_template.py,sha256=MWSv2fLKGJxdt2zfSO0b74peuBC8U9j_S6AwM5URXts,14945
         | 
| 22 | 
            +
            dendrotweaks/biophys/default_templates/default.py,sha256=7HEbR2GJEOhgiox1QtZUEuHi5ihNAHDLsXQiQk980tI,2201
         | 
| 23 | 
            +
            dendrotweaks/biophys/default_templates/standard_channel.mod,sha256=sw80c-JyqfXNA7c7v7pZGLY-0MgFUvd3bPvJcAGXNSk,2923
         | 
| 24 | 
            +
            dendrotweaks/biophys/default_templates/template_jaxley.py,sha256=t-GsCSUyQ7rDoaLmyuWd9bIxB8W3bCqJdnikD59EVvI,3676
         | 
| 25 | 
            +
            dendrotweaks/biophys/default_templates/template_jaxley_new.py,sha256=I62KhnOYNV1bT-nPsDTxjIISYmDcso2X8rnsos28nYs,3631
         | 
| 26 | 
            +
            dendrotweaks/biophys/io/__init__.py,sha256=kkmQ4L0SatI3lWd3qE8KqOIKd7x3G2OnqAAW93sWWCU,575
         | 
| 27 | 
            +
            dendrotweaks/biophys/io/ast.py,sha256=7x_Kxz1qoQHZeIjovUNyVuKgUo4vAFKm-bd4hn9n1CI,6078
         | 
| 28 | 
            +
            dendrotweaks/biophys/io/code_generators.py,sha256=yg0Do1XLM_rIXk4i_FibJGfkWOt-GN0lq5dOCD4D3pk,11702
         | 
| 29 | 
            +
            dendrotweaks/biophys/io/converter.py,sha256=5yrPJhyZbuwV7tTGoacnNOvmRdVgXPIyGfiR0PyOVzg,3371
         | 
| 30 | 
            +
            dendrotweaks/biophys/io/factories.py,sha256=j1Hi2u-NTFFL8ElRYlgGVNHRcfKWH6o5GfKvraMTlwM,5020
         | 
| 31 | 
            +
            dendrotweaks/biophys/io/grammar.py,sha256=TJLTDlr8Ajp3J9DJ4IvulOCcpUkYr7HnoI0TGnNuEPc,11677
         | 
| 32 | 
            +
            dendrotweaks/biophys/io/loader.py,sha256=Wv9ZkEDyA3MkCdV0sMeRnBffg2WAI7yTV3r6C412GiY,6378
         | 
| 33 | 
            +
            dendrotweaks/biophys/io/parser.py,sha256=boT27lFrn5LYrJnkZFs0SwrZZrkSkwO8efqGPJ4Qj0I,17914
         | 
| 34 | 
            +
            dendrotweaks/biophys/io/reader.py,sha256=JWm5WM9illvSfDkhWEmWBcj8Y7PSi8zeZX9j1ARUHVU,6576
         | 
| 35 | 
            +
            dendrotweaks/morphology/__init__.py,sha256=aqJTQOpRVOYcbWqZ2q4e-Oy735r9_ubW-uE_5cFZVtI,323
         | 
| 36 | 
            +
            dendrotweaks/morphology/domains.py,sha256=Y4txcGdBdl2aK1DfbTRziNtDyd6bChczwpCWE7lTFzg,2391
         | 
| 37 | 
            +
            dendrotweaks/morphology/point_trees.py,sha256=5dUPaQXYPdJbWoD3pFI2DV2XnuFRhB5d0wTBlfmmIeI,21600
         | 
| 38 | 
            +
            dendrotweaks/morphology/sec_trees.py,sha256=4EU8YbYsi1Pr_n7vkFuKQtIIWbJwP-8Q_epmioEXAIw,36902
         | 
| 39 | 
            +
            dendrotweaks/morphology/seg_trees.py,sha256=uwL1X9qeFNyJVHua1I3rhp0fLSRrS2TAVyb1Fnw4RwQ,3595
         | 
| 40 | 
            +
            dendrotweaks/morphology/trees.py,sha256=NrNvPMR-U0clt63eqwVJqU0H8NJgY53QGA_BkdcwkQI,16033
         | 
| 41 | 
            +
            dendrotweaks/morphology/io/__init__.py,sha256=gAZqZdf5VKPb6ksK8Lwt7MbTAq8TDP8uq3Vs_ebNFEY,324
         | 
| 42 | 
            +
            dendrotweaks/morphology/io/factories.py,sha256=NngNINw73diGK7fud314JzWVhxv2aYLuA9wUuQA0Diw,6344
         | 
| 43 | 
            +
            dendrotweaks/morphology/io/reader.py,sha256=hW3c541WtG1rNag_YreEhvrLzm8-OTtw0fQREeHDthM,1913
         | 
| 44 | 
            +
            dendrotweaks/morphology/io/validation.py,sha256=lVkYw9y9yG5QpRh_N0YQ3FbZwuSUsQfSqJTMumMcDdc,7872
         | 
| 45 | 
            +
            dendrotweaks/morphology/reduce/__init__.py,sha256=p6Mg3KDHxTt8S4DtI0m7L7MqV6dS2pdIYAwB7B-toVw,921
         | 
| 46 | 
            +
            dendrotweaks/morphology/reduce/reduce.py,sha256=5czZDrG3xsvHn3c_tbYhUOlXgST989-RS-ntbhlvvA0,6361
         | 
| 47 | 
            +
            dendrotweaks/morphology/reduce/reduced_cylinder.py,sha256=jGJ4J-amukRr-3DPirVR5pzNO-6H7_sZF1N_X57ZGdw,5132
         | 
| 48 | 
            +
            dendrotweaks/stimuli/__init__.py,sha256=bFfSEZhCVpwOVEBgLe65iiY3SdpjKPhyLemC1z5OX9I,153
         | 
| 49 | 
            +
            dendrotweaks/stimuli/iclamps.py,sha256=NjkhhwZKJR1f_g3N9BVxMVoO9ubBk5WkQ6h9Bnf9xgA,1681
         | 
| 50 | 
            +
            dendrotweaks/stimuli/populations.py,sha256=y85v8smiMifINIqXm1O3mOINAlDTz-SPGLS78alhX5A,8325
         | 
| 51 | 
            +
            dendrotweaks/stimuli/synapses.py,sha256=g4MgWTske2TZ2i9FIIOE8-KXNx_3dWa3zEhB2rcqYig,5470
         | 
| 52 | 
            +
            dendrotweaks-0.4.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
         | 
| 53 | 
            +
            dendrotweaks-0.4.0.dist-info/METADATA,sha256=9AAcxk2ZzIvqUOQg7hNf0Tw1an2EYJLl76gSI21WAKM,2740
         | 
| 54 | 
            +
            dendrotweaks-0.4.0.dist-info/WHEEL,sha256=lTU6B6eIfYoiQJTZNc-fyaR6BpL6ehTzU3xGYxn2n8k,91
         | 
| 55 | 
            +
            dendrotweaks-0.4.0.dist-info/top_level.txt,sha256=OzT_2BSI5j5zxC447K6Y-0W-GHbued7iX-_hFGAKMxY,13
         | 
| 56 | 
            +
            dendrotweaks-0.4.0.dist-info/RECORD,,
         | 
| @@ -1,6 +0,0 @@ | |
| 1 | 
            -
            from dendrotweaks.membrane.mechanisms import Mechanism, IonChannel, CaDynamics, StandardIonChannel, LeakChannel
         | 
| 2 | 
            -
            from dendrotweaks.membrane.mechanisms import LeakChannel
         | 
| 3 | 
            -
            from dendrotweaks.membrane.groups import SegmentGroup
         | 
| 4 | 
            -
            from dendrotweaks.membrane.distributions import Distribution
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            import dendrotweaks.membrane.io as io
         | 
| @@ -1,11 +0,0 @@ | |
| 1 | 
            -
            from dendrotweaks.membrane.io.loader import MODFileLoader
         | 
| 2 | 
            -
            from dendrotweaks.membrane.io.converter import MODFileConverter
         | 
| 3 | 
            -
             | 
| 4 | 
            -
            from dendrotweaks.membrane.io.reader import MODFileReader
         | 
| 5 | 
            -
            from dendrotweaks.membrane.io.parser import MODFileParser
         | 
| 6 | 
            -
            from dendrotweaks.membrane.io.code_generators import PythonCodeGenerator
         | 
| 7 | 
            -
            from dendrotweaks.membrane.io.code_generators import NMODLCodeGenerator
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            from dendrotweaks.membrane.io.factories import create_channel
         | 
| 10 | 
            -
            from dendrotweaks.membrane.io.factories import create_standard_channel
         | 
| 11 | 
            -
            from dendrotweaks.membrane.io.factories import standardize_channel
         |