Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Addition of membrane comp/transport mech #265

Open
wants to merge 17 commits into
base: dev
Choose a base branch
from
Open
56 changes: 56 additions & 0 deletions Tests/Unit/test_component_membrane.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright (c) 2020, Build-A-Cell. All rights reserved.
# See LICENSE file in the project root directory for details.

from biocrnpyler import IntegralMembraneProtein, MembraneChannel, MembranePump
import pytest


def test_IntegralMembraneProtein():
membrane_protein = 'MP1'
products = 'P1'

mp = IntegralMembraneProtein(membrane_protein=membrane_protein, product=products)
assert membrane_protein == mp.membrane_protein.name
assert products== mp.product.name

assert mp.get_species().name == 'MP1'

with pytest.raises(KeyError, match='Unable to find mechanism of type catalysis in Component'):
mp.update_species()

with pytest.raises(KeyError, match='Unable to find mechanism of type catalysis in Component'):
mp.update_reactions()

def test_MembraneChannel():
integral_membrane_protein = 'IMP1'
substrates = 'S1'

imp = MembraneChannel(integral_membrane_protein, substrate=substrates)
assert integral_membrane_protein == imp.integral_membrane_protein.name
assert substrates == imp.substrate.name
assert substrates == imp.product.name

assert imp.get_species().name == 'IMP1'

with pytest.raises(KeyError, match='Unable to find mechanism of type catalysis in Component'):
imp.update_species()

with pytest.raises(KeyError, match='Unable to find mechanism of type catalysis in Component'):
imp.update_reactions()

def test_MembranePump():
membrane_pump = 'MPump1'
substrates = 'S1'

imp = MembranePump(membrane_pump, substrate=substrates)
assert membrane_pump == imp.membrane_pump.name
assert substrates == imp.substrate.name
assert substrates == imp.product.name

assert imp.get_species().name == 'MPump1'

with pytest.raises(KeyError, match='Unable to find mechanism of type catalysis in Component'):
imp.update_species()

with pytest.raises(KeyError, match='Unable to find mechanism of type catalysis in Component'):
imp.update_reactions()
89 changes: 89 additions & 0 deletions Tests/Unit/test_transport.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@

# Copyright (c) 2020, Build-A-Cell. All rights reserved.
# See LICENSE file in the project root directory for details.

from biocrnpyler import Species, Complex

#Test Membrane Transport Mechanisms
from biocrnpyler import Membrane_Protein_Integration, Passive_Transport, Facilitated_Passive_Transport, Primary_Active_Transport

class test_membrane_integration():
mpi = Membrane_Protein_Integration()
MP = Species("MP1")
MP.size=2
IMP = Species("IMP1")
c1 = Complex([MP]*MP.size)
c_fake = Species("C")

#Test Update Species
assert len(mpi.update_species(MP, IMP)) == 4
assert c1 in mpi.update_species(MP, IMP)
assert c_fake in mpi.update_species(MP, IMP, complex = c_fake)

#Test Update Reactions
assert len(mpi.update_reactions(MP, IMP, kb = 1.0, kd = 1.0, ku = 1.0, kcat = 1.0, kex = 1.0)) == 4
assert len(mpi.update_reactions(MP, IMP, kb = 1.0, kd = 1.0, ku = 1.0, kcat = 1.0, kex = 1.0, complex_species = c_fake,)) == 4

class test_passive_transport():
pt = Passive_Transport2()
MC = Species("MC1")
substrate = Species("S1")
product = Species("P1")

c_fake = Species("C")

#Test Update Species
assert len(pt.update_species(MC, substrate, product)) == 5
assert c_fake in pt.update_species(MC, substrate, product, complex = c_fake)

#Test Update Reactions
assert len(pt.update_reactions(MC, substrate, product, k_channel = 1.0)) == 1
assert len(pt.update_reactions(MC, substrate, product, k_channel = 1.0, complex_species = c_fake,)) == 1

class test_facilitated_passive_transport():
fpt = Facilitated_Passive_Transport2()
MC = Species("MC1")
substrate = Species("S1")
product = Species("P1")
c1 = Complex([substrate, MC])
c2 = Complex([product, MC])
c_fake = Species("C")

#Test Update Species
assert len(fpt.update_species(MC, substrate, product)) == 5
assert c1 in fpt.update_species(MC, substrate, product)
assert c2 in fpt.update_species(MC, substrate, product)
assert c_fake in fpt.update_species(MC, substrate, product, complex = c_fake)

#Test Update Reactions
assert len(fpt.update_reactions(MC, substrate, product, kb = 1.0, ku = 1.0, k1 = 1.0)) == 4
assert len(fpt.update_reactions(MC, substrate, product, kb = 1.0, ku = 1.0, k1 = 1.0, complex_species = c_fake,)) == 4

class test_active_transport():
pat = Primary_Active_Transport2()
MP = Species("MC1")
MP.ATP=2
substrate = Species("S1")
product = Species("P1")
energy = Species("E1")
waste = Species("W1")
c1 = Complex([substrate, MP])
c2 = Complex([product, MP])
c3 = Complex([MP.ATP*[energy], c1])
c4 = Complex([MP.ATP*[waste], c2])

c_fake = Species("C")

#Test Update Species
assert len(pat.update_species(MP, substrate, product, energy, waste)) == 7
assert c1 in pat.update_species(MP, substrate, product, energy, waste)
assert c2 in pat.update_species(MP, substrate, product, energy, waste)
assert c3 in pat.update_species(MP, substrate, product, energy, waste)
assert c4 in pat.update_species(MP, substrate, product, energy, waste)

assert c_fake in pat.update_species(MP, substrate, product, energy, waste, complex = c_fake)

#Test Update Reactions
assert len(pat.update_reactions(MP, substrate, product, energy, waste, kb = 1.0, ku = 1.0, kcat = 1.0, kex = 1.0)) == 7
assert len(pat.update_reactions(MP, substrate, product, energy, waste, kb = 1.0, ku = 1.0, kcat = 1.0, kex = 1.0, complex_species = c_fake,)) == 7

3 changes: 3 additions & 0 deletions biocrnpyler/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from .integrase_enumerator import *
from .components_combinatorial_complex import *
from .components_combinatorial_conformation import *
from .components_membrane import *

from .global_mechanism import *
from .mechanism import *
Expand All @@ -25,6 +26,8 @@
from .mechanisms_enzyme import *
from .mechanisms_txtl import *
from .mechanisms_integrase import *
from .mechanisms_transport import *

# Core classes
from .mixture import *
from .mixtures_cell import *
Expand Down
7 changes: 5 additions & 2 deletions biocrnpyler/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,21 @@ def get_species(self) -> None:
"""
return None
@classmethod
def set_species(self, species: Union[Species, str], material_type=None, attributes=None) -> Species:
def set_species(self, species: Union[Species, str], material_type=None,
compartment=None, attributes=None) -> Species:
"""Helper function that allows species to be set from strings, species, or Components

:param species: Species, str, Component
:param material_type:
:param compartment:
:param attributes:
:return: Species
"""
if isinstance(species, Species):
return species
elif isinstance(species, str):
return Species(name=species, material_type=material_type, attributes=attributes)
return Species(name=species, material_type=material_type,
compartment=compartment, attributes=attributes)
elif isinstance(species, Component) and species.get_species() is not None:
return species.get_species()
elif isinstance(species, list):
Expand Down
198 changes: 198 additions & 0 deletions biocrnpyler/components_membrane.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@

# Copyright (c) 2020, Build-A-Cell. All rights reserved.
# See LICENSE file in the project root directory for details.

from typing import List, Union

from .component import Component
from .reaction import Reaction
from .species import Complex, Species

class IntegralMembraneProtein(Component):
"""A class to represent transmembrane proteins or integral membrane proteins.
This membrane class is to classify a membrane channel that will intergrate into the membrane.
Uses a mechanism called "catalysis".
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused why membrane proteins are Enzymes by default. Is there an example you have in mind?

Size is used to indicate number of repeating components to create oligomer. Dimer =2, Trimers = 3, etc."
"""
def __init__(self, membrane_protein: Union[Species, str, Component],
product: Union[Species,str, Component],
direction= None, size=None, attributes=None, **keywords):
"""Initialize a MembraneChannel object to store membrane channel related information.
:param product: name of the membrane channel, reference to an Species or Component
:param direction: transport direction, taken as "Passive"-undirectional unless specified
:param size: number of monomers needed for channel
:param attributes: Species attribute
:param keywords: pass into the parent's (Component) initializer
"""

# PROTEIN
self.membrane_protein = self.set_species(membrane_protein, material_type='protein', attributes=attributes)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#Set Internal and Membrane Compartments
self.internal_compartment = ...
self.membrane_compartment = ...

self.membrane_protein_free = self.set_species(membrane_protein, material_type = 'protein', compartment = internal_compartment, attributes = attributes)

self.membrane_protein_integrated = self.set_species(membrane_protein, material_type = 'protein', attributes = attributes, compartment = membrane_compartment)


# PRODUCT is an integrated membrane protein (transmembrane_protein)
if product is None:
if direction is None:
self.product = self.set_species(product, material_type= 'Passive')
else:
self.product = self.set_species(product, material_type= direction)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'passive' and direction do not seem like materials a molecule is built out of. Maybe I am missing something about what you are doing here though.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be an attribute?


else:
if direction is None:
self.product = self.set_species(product, material_type= 'Passive')
else:
self.product = self.set_species(product, material_type= direction)

if size is None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is size being used for?

self.membrane_protein.size = 1
else:
self.membrane_protein.size = size

Component.__init__(self=self, name=self.membrane_protein.name, **keywords)

def get_species(self):
return self.membrane_protein

def update_species(self):
mech_cat = self.get_mechanism('catalysis')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a different type of mechanism e.g. 'membrane_insertion'


return mech_cat.update_species(self.membrane_protein, self.product)

def update_reactions(self):
mech_cat = self.get_mechanism('catalysis')
print(self)

return mech_cat.update_reactions(self.membrane_protein, self.product, component=self, part_id=self.name)

class MembraneChannel(Component):
"""A class to represent Membrane Channels.
Assumes the membrane channel transport substrates in a specific direction across the membrane
Uses a mechanism called "catalysis"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better for the mechanism type to be called "transport" - otherwise, if we cannot use your transport Mechanisms at the same time a different catalysis mechanism is used (say for metabolism).

"""
def __init__(self, integral_membrane_protein: Union[Species, str, Component],
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all the inits, can you add compartment keywords e.g. internal_compartment = "Internal"

substrate: Union[Species, str, Component],
direction=None, attributes=None, **keywords):
"""Initialize a Transporter object to store Transport membrane related information.
:param substrate: name of the substrate, reference to an Species or Component
:param direction: give direction of transport ref to vesicle
:param attributes: Species attribute
:param keywords: pass into the parent's (Component) initializer
"""

# SUBSTRATE
if substrate is None:
self.substrate = None
else:
product=substrate
self.substrate = self.set_species(substrate, compartment='Internal',attributes=attributes)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I usually think of catalysis as substrate --> product. Why are you setting substrate = product?

self.product= self.set_species(product, compartment='External',attributes=attributes)

# PROTEIN
if type(integral_membrane_protein) == str:
if direction == None:
self.integral_membrane_protein = self.set_species(integral_membrane_protein, material_type='Passive', attributes=attributes)
else:
self.integral_membrane_protein = self.set_species(integral_membrane_protein, material_type=direction, attributes=attributes)
if direction == 'Importer':
if substrate is None:
self.substrate = None
else:
product=substrate
self.substrate = self.set_species(substrate, compartment='External',attributes=attributes)
self.product= self.set_species(product, compartment='Internal',attributes=attributes)
else:
if integral_membrane_protein.material_type == 'Passive':
self.integral_membrane_protein = self.set_species(integral_membrane_protein, material_type='Passive', attributes=attributes)
elif integral_membrane_protein.material_type == 'Exporter':
self.integral_membrane_protein = self.set_species(integral_membrane_protein, material_type='Exporter', attributes=attributes)
elif integral_membrane_protein.material_type == 'Importer':
self.integral_membrane_protein = self.set_species(integral_membrane_protein, material_type='Importer', attributes=attributes)

if substrate is None:
self.substrate = None
else:
product=substrate
self.substrate = self.set_species(substrate, compartment='External',attributes=attributes)
self.product= self.set_species(product, compartment='Internal',attributes=attributes)

else:
print('Membrane channel direction not found.')

Component.__init__(self=self, name=self.integral_membrane_protein.name, **keywords)

#######################
print(self.attributes)

def get_species(self):
return self.integral_membrane_protein

def update_species(self):
mech_cat = self.get_mechanism('catalysis')
return mech_cat.update_species(self.integral_membrane_protein, self.substrate, self.product)

def update_reactions(self):
mech_cat = self.get_mechanism('catalysis')
return mech_cat.update_reactions(self.integral_membrane_protein, self.substrate, self.product, component=self, part_id=self.name)

class MembranePump(Component):
"""A class to represent Membrane Channels.
Assumes the membrane channel transport substrates in a specific direction across the membrane
Uses a mechanism called "catalysis"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above comment on mechanism type.

"""
def __init__(self, membrane_pump: Union[Species, str, Component],
substrate: Union[Species, str, Component],
ATP=None,
attributes=None, **keywords):
"""Initialize a Transporter object to store Transport membrane related information.
:param substrate: name of the substrate, reference to an Species or Component
:param direction: give direction of transport ref to vesicle
:param attributes: Species attribute
:param keywords: pass into the parent's (Component) initializer
"""
# PROTEIN
self.membrane_pump = self.set_species(membrane_pump, material_type='protein', attributes=attributes)

# SUBSTRATE
if substrate is None:
self.substrate = None
else:
product=substrate
self.substrate = self.set_species(substrate, compartment='Internal',attributes=attributes)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can internal_compartment and external_compartment be variables set in the constructor 'internal' and 'external' are great defaults, but it would be nice to be able to change the compartment names.

self.product= self.set_species(product, compartment='External',attributes=attributes)

if ATP is None:
self.membrane_pump.ATP= 1
else:
self.membrane_pump.ATP = ATP

self.energy = self.set_species('ATP', material_type='small_molecule', compartment='Internal',attributes=attributes)
self.waste = self.set_species('ADP', material_type='small_molecule', compartment='Internal',attributes=attributes)

if membrane_pump.material_type == 'Exporter':
self.membrane_pump = self.set_species(membrane_pump, material_type='Exporter', attributes=attributes)
elif membrane_pump.material_type == 'Importer':
self.membrane_pump = self.set_species(membrane_pump, material_type='Importer', attributes=attributes)

if substrate is None:
self.substrate = None
else:
product=substrate
self.substrate = self.set_species(substrate, compartment='External',attributes=attributes)
self.product= self.set_species(product, compartment='Internal',attributes=attributes)

else:
print('Membrane channel direction not found.')

Component.__init__(self=self, name=membrane_pump.name, **keywords)

#######################
print(self.attributes)

def get_species(self):
return self.membrane_pump

def update_species(self):
mech_cat = self.get_mechanism('catalysis')
return mech_cat.update_species(self.membrane_pump, self.substrate, self.product, self.energy, self.waste)

def update_reactions(self):
mech_cat = self.get_mechanism('catalysis')
return mech_cat.update_reactions(self.membrane_pump, self.substrate, self.product, self.energy, self.waste, component=self, part_id=self.name)
Loading