Skip to content

Commit 4811b83

Browse files
committed
Initial commit of JDP titin addition
Joe Powers spent a considerable amount of effort incorporating titin into the model. Here’s the lion’s share of his work added in, starting from the point he initially pulled from the repo.
1 parent 761adc6 commit 4811b83

4 files changed

Lines changed: 223 additions & 4 deletions

File tree

multifil/af.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,10 @@ def from_dict(self, tfd):
190190
self.binding_sites = [self.parent_thin.resolve_address(bsa) \
191191
for bsa in tfd['binding_sites']]
192192

193+
def link_titin(self, titin_fil):
194+
"""Add a titin filament to this face"""
195+
self.titin_fil = titin_fil
196+
193197
def nearest(self, axial_location):
194198
"""Where is the nearest binding site?
195199

multifil/hs.py

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import scipy.optimize as opt
1717
from . import af
1818
from . import mf
19+
from . import ti
1920

2021
class hs:
2122
"""The half-sarcomere and ways to manage it"""
@@ -249,6 +250,56 @@ def __init__(self, lattice_spacing=None, z_line=None, poisson=None,
249250
self.actin_permissiveness = actin_permissiveness
250251
# Track how long we've been running
251252
self.current_timestep = 0
253+
# Create the titin filaments and link them from thick
254+
# faces to thin faces
255+
# |--------------------------------------------------|
256+
# | Actin & titin around myosin |
257+
# |--------------------------------------------------|
258+
# | a1 a3 |
259+
# | |
260+
# | a0 t1 a2 t4 a0 |
261+
# | t0 t2 t3 t5 |
262+
# | M0 M1 |
263+
# | t6 t8 t9 t11 |
264+
# | a4 t7 a6 t10 a4 |
265+
# | |
266+
# | a5 t13 a7 t16 a5 |
267+
# | t12 t14 t15 t17 |
268+
# | M2 M3 |
269+
# | t18 t20 t21 t23 a1 |
270+
# | a1 t19 a3 t22 |
271+
# | |
272+
# | a2 a0 |
273+
# |--------------------------------------------------|
274+
## CHECK_JDP ## Link Thick filament to titin
275+
ti_thick = lambda i, j: self.thick[i].thick_faces[j]
276+
ti_thin = lambda i, j: self.thin[i].thin_faces[j]
277+
self.titin = (
278+
ti.Titin(self, 0, ti_thick(0, 0), ti_thin(0, 1)),
279+
ti.Titin(self, 1, ti_thick(0, 1), ti_thin(1, 2)),
280+
ti.Titin(self, 2, ti_thick(0, 2), ti_thin(2, 2)),
281+
ti.Titin(self, 3, ti_thick(1, 0), ti_thin(2, 1)),
282+
ti.Titin(self, 4, ti_thick(1, 1), ti_thin(3, 2)),
283+
ti.Titin(self, 5, ti_thick(1, 2), ti_thin(0, 2)),
284+
ti.Titin(self, 6, ti_thick(0, 5), ti_thin(4, 1)),
285+
ti.Titin(self, 7, ti_thick(0, 4), ti_thin(5, 0)),
286+
ti.Titin(self, 8, ti_thick(0, 3), ti_thin(6, 0)),
287+
ti.Titin(self, 9, ti_thick(1, 5), ti_thin(6, 1)),
288+
ti.Titin(self, 10, ti_thick(1, 4), ti_thin(7, 0)),
289+
ti.Titin(self, 11, ti_thick(1, 3), ti_thin(4, 0)),
290+
ti.Titin(self, 12, ti_thick(2, 0), ti_thin(5, 1)),
291+
ti.Titin(self, 13, ti_thick(2, 1), ti_thin(6, 2)),
292+
ti.Titin(self, 14, ti_thick(2, 2), ti_thin(7, 2)),
293+
ti.Titin(self, 15, ti_thick(3, 0), ti_thin(7, 1)),
294+
ti.Titin(self, 16, ti_thick(3, 1), ti_thin(4, 2)),
295+
ti.Titin(self, 17, ti_thick(3, 2), ti_thin(5, 2)),
296+
ti.Titin(self, 18, ti_thick(2, 5), ti_thin(1, 1)),
297+
ti.Titin(self, 19, ti_thick(2, 4), ti_thin(2, 0)),
298+
ti.Titin(self, 20, ti_thick(2, 3), ti_thin(3, 0)),
299+
ti.Titin(self, 21, ti_thick(3, 5), ti_thin(3, 1)),
300+
ti.Titin(self, 22, ti_thick(3, 4), ti_thin(0, 0)),
301+
ti.Titin(self, 23, ti_thick(3, 3), ti_thin(1, 0)),
302+
)
252303

253304
def to_dict(self):
254305
"""Create a JSON compatible representation of the thick filament
@@ -489,7 +540,8 @@ def radialtension(self):
489540

490541
def radialforce(self):
491542
"""The sum of the thick filaments' radial forces, as a (y,z) vector"""
492-
return np.sum([t.radial_force_of_filament() for t in self.thick], 0)
543+
return np.sum([t.radial_force_of_filament() for t in self.thick], 0)# + ...
544+
#sum([titin.radialforce() for titin in self.titin]) #CHECK
493545

494546
def _single_settle(self):
495547
"""Settle down now, just a little bit"""
@@ -516,6 +568,25 @@ def _get_residual(self):
516568
mash = np.hstack([thick_f, thin_f])
517569
return mash
518570

571+
def length_perturbation(self, dist=None, n=None):
572+
"""Get the force response of the half-sarcomere to a length perturbation"""
573+
if dist is None:
574+
dist = 0.2; #take length perturbation steps of 'dist' nm
575+
if n is None:
576+
n = 10; #take 'n' length perturbation steps.
577+
response = [];
578+
stiffness = [];
579+
initial_force = self.axialforce()
580+
initial_zline = self.z_line
581+
for i in range(n):
582+
self.z_line += dist
583+
self.settle()
584+
response.append(((i+1) * dist, self.axialforce() - initial_force))
585+
stiffness.append((self.axialforce() - initial_force) / ((i+1) * dist))
586+
self.z_line = initial_zline
587+
self.settle()
588+
return np.mean(stiffness)
589+
519590
def get_frac_in_states(self):
520591
"""Calculate the fraction of cross-bridges in each state"""
521592
nested = [t.get_states() for t in self.thick]
@@ -524,6 +595,12 @@ def get_frac_in_states(self):
524595
frac_in_state = [n/float(len(xb_states)) for n in num_in_state]
525596
return frac_in_state
526597

598+
#ADDED BY JDP ON 2017-Aug-21
599+
def get_31_trans(self):
600+
"""Calculate the number of xb's that transition from state 3 to 1"""
601+
xb_trans = sum(sum(self.last_transitions,[]),[])
602+
return xb_trans.count('31')
603+
527604
def update_ls_from_poisson_ratio(self):
528605
"""Update the lattice spacing consistant with the poisson ratio,
529606
initial lattice spacing, current z-line, and initial z-line

multifil/mf.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"""
88

99
from . import mh
10+
from . import ti
1011
import numpy as np
1112

1213

@@ -223,6 +224,10 @@ def to_dict(self):
223224
for xb in thickfaced['xb_by_crown']]
224225
return thickfaced
225226

227+
def link_titin(self, titin_fil):
228+
"""Add a titin filament to this face"""
229+
self.titin_fil = titin_fil
230+
226231
def from_dict(self, tfd):
227232
""" Load values from a thick face dict. Values read in correspond
228233
to the current output documented in to_dict.
@@ -258,6 +263,7 @@ def axialforce(self):
258263
def radialtension(self):
259264
"""Sum of the absolute values of radial force for every myosin"""
260265
radial = [crossbridge.radialforce() for crossbridge in self.xb]
266+
radial.append(self.titin.radialforce())
261267
return sum(radial)
262268

263269
def radialforce(self):
@@ -563,7 +569,6 @@ def settle(self):
563569
forces = self.axialforce()
564570
# Individual displacements needed to balance force
565571
isolated = 0.95*forces/self.k
566-
isolated[-1] *= 2 # Last node has spring on only one side
567572
# Cumulative displacements
568573
cumulative = np.cumsum(isolated)
569574
# New axial locations
@@ -648,11 +653,28 @@ def _axial_thick_filament_forces(self, axial_locations=None):
648653
# Find the distance from crown to crown, then the resulting forces
649654
dists = np.diff(axial_locations)
650655
spring_force = (dists - self.rests) * self.k
651-
spring_force = np.hstack([spring_force, 0]) # Last node not connected
652-
# Zero would be the force of titin, were it in the model
656+
# Location zero is the force of titin
657+
net_force_at_crown = np.diff(spring_force)
658+
titin_force = self._normed_total_titin_force()
659+
spring_force = np.hstack([spring_force, titin_force])
653660
net_force_at_crown = np.diff(spring_force)
654661
return net_force_at_crown
655662

663+
def _normed_total_titin_force(self):
664+
"""Settle expects to move nodes to satisfy springs of stiffness self.k.
665+
Titin has a different stiffness. We express the force titin is
666+
generating in terms of the thick fil stiffness in order to treat the
667+
movement necessary to balance the node attached to titin the same as
668+
the movement necessary to balance the force of the thick filaments.
669+
"""
670+
normed_titin_forces = []
671+
for thick_face in self.thick_faces:
672+
titin = thick_face.titin_fil
673+
titin_force = titin.axialforce()
674+
normed = titin_force * titin.stiffness() / self.k
675+
normed_titin_forces.append(normed)
676+
return np.sum(normed_titin_forces)
677+
656678
@staticmethod
657679
def _radial_force_to_components(crown_force, orientation):
658680
"""Convert radial components of a crown's force into a y,z vector

multifil/ti.py

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/bin/env python
2+
# encoding: utf-8
3+
"""
4+
ti.py - A titin filament, with variable compliance
5+
6+
MORE ABOUT HOW TITIN WORKS
7+
8+
Created by Joe Powers and Dave Williams on 2017-02-17
9+
"""
10+
11+
12+
import numpy as np
13+
import warnings
14+
import numpy.random as random
15+
random.seed() # Ensure proper seeding
16+
17+
18+
class Titin:
19+
"""This is all about the titin filament"""
20+
def __init__(self, parent_lattice, index, thick_face, thin_face,
21+
a=240, b=0.0045):
22+
"""Initialize the titin filament.
23+
24+
Parameters:
25+
parent_lattice: calling half-sarcomere instance
26+
index: which titin filament this is (0-23)
27+
thick_face: List of thick filament faces' numerical orientation (0-5)
28+
thin_face: List of thin filament faces' numerical orientation (0-2)
29+
30+
Returns:
31+
None
32+
"""
33+
# Name of the titin molecule
34+
self.index = index
35+
# A connection to the parent lattice
36+
self.parent_lattice = parent_lattice
37+
# Location of the titin filament relative thick filament
38+
self.thick_face = thick_face
39+
# Link titin to the thick filament face
40+
self.thick_face.link_titin(self)
41+
# location of the titin filament relative to the thin filament
42+
self.thin_face = thin_face
43+
# Link titin to that face of the thin filament
44+
self.thin_face.link_titin(self)
45+
## And now we declare titin properties that will be used to
46+
## calculate forces
47+
self.rest = 120 #nm, no citation
48+
# Create the constants that determine force NOTE IMPROVE DOC
49+
self.a = a
50+
self.b = b
51+
52+
def angle(self):
53+
"""Caclulate the angle the titin makes relative to thick filament"""
54+
act_loc = self.thin_face.parent_thin.parent_lattice.z_line
55+
myo_loc = self.thick_face.get_axial_location(-1)
56+
ls = self.parent_lattice.lattice_spacing
57+
angle = np.arctan2(ls, act_loc-myo_loc)
58+
return angle
59+
60+
def length(self):
61+
"""Calculate the length of the titin filament"""
62+
act_loc = self.thin_face.parent_thin.parent_lattice.z_line
63+
myo_loc = self.thick_face.get_axial_location(-1)
64+
ls = self.parent_lattice.lattice_spacing
65+
length = np.sqrt( (act_loc-myo_loc)**2 + ls**2 )
66+
return length
67+
68+
def stiffness(self):
69+
"""Need instintanious stiffness at the current length to normalize
70+
force for settling at each timestep. We get this as the derivitive of
71+
force with respect to x. D[a*exp(b*x), x] = a*b*exp(b*x)
72+
"""
73+
return self.force()*self.b
74+
75+
def force(self):
76+
"""Calculate the total force the titin filament exerts"""
77+
length = self.length()
78+
if length < self.rest:
79+
return 0 # titin buckles
80+
else:
81+
#Exponential Model
82+
x = length - self.rest
83+
return self.a*np.exp(self.b*x)
84+
#else:
85+
#Cubic model
86+
#x = length - self.rest
87+
#a = 3.25e-5
88+
#b = -5e-3
89+
#c = 9e-1
90+
#d = -7e-5
91+
#return a*(x**3) + b*(x**2) + c*x + d #Linke et al. PNAS 1998
92+
#else:
93+
# Sawtooth Model
94+
#extension = length - self.rest
95+
#a = 1.2e-6
96+
#b = 3
97+
#c = 0.5e-6#*random.rand()
98+
#d = 34
99+
#e = 3
100+
#return a*extension**b + c*np.fmod(extension,d)**e
101+
#else:
102+
#Hookean Model
103+
#return self.k * (self.length() - self.rest)
104+
105+
def axialforce(self):
106+
"""Return the total force the titin filament exerts on the
107+
thick filament's final node, (negate for the thin filament side)
108+
"""
109+
return self.force() * np.cos(self.angle()) ## CHECK_JDP ##
110+
111+
def radialforce(self):
112+
"""Return the force in the radial direction (positive is compressive)
113+
TODO: The 'positive is compressive' part needs to be double checked
114+
"""
115+
warnings.warn("Check radial force direction in titin")
116+
return self.force() * np.sin(self.angle())

0 commit comments

Comments
 (0)