Skip to content

Commit aa8c2d8

Browse files
authored
Add atom-in-cyclinder features (#45)
This adds a far simpler criterion than the "inside hull" for choosing atoms and/or residues for inclusion in the feature GMM. This can be used to cross-check a result to ensure it's not dependent on subtle variations in angle. This also tweaks `align_to_membrane` to pair more naturally with this atom-selection method, and improves its docstring.
1 parent 24d60c4 commit aa8c2d8

File tree

5 files changed

+56
-8
lines changed

5 files changed

+56
-8
lines changed

Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name = "GPCRAnalysis"
22
uuid = "c1d73f9e-d42a-418a-8d5b-c7b00ec0358f"
3-
version = "0.6.1"
3+
version = "0.6.2"
44
authors = ["Tim Holy <[email protected]> and contributors"]
55

66
[deps]
@@ -15,6 +15,7 @@ GaussianMixtureAlignment = "f2431ed1-b9c2-4fdb-af1b-a74d6c93b3b3"
1515
HTTP = "cd3eb016-35fb-5094-929b-558a96fad6f3"
1616
Hungarian = "e91730f6-4275-51fb-a7a0-7064cfbd3b39"
1717
Interpolations = "a98d9a8b-a2ab-59e6-89dd-64a1c18fca59"
18+
IntervalSets = "8197267c-284f-5f27-9208-e0e47529a953"
1819
JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1"
1920
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2021
MultivariateStats = "6f286f6a-111f-5878-ab1e-185364afe411"
@@ -51,6 +52,7 @@ HTTP = "1"
5152
HiGHS = "1"
5253
Hungarian = "0.6, 0.7"
5354
Interpolations = "0.15, 0.16"
55+
IntervalSets = "0.7.11"
5456
JSON3 = "1"
5557
JuMP = "1"
5658
LinearAlgebra = "1"

src/GPCRAnalysis.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ using Hungarian
1515
using ProgressMeter
1616
using StaticArrays
1717
using Rotations
18+
using IntervalSets
1819
using TravelingSalesmanHeuristics
1920

2021
using Interpolations

src/align.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ and false otherwise.
8888
8989
`applytransform!(chain, tform)` (or the `model` that includes `chain`) will
9090
re-orient `chain` so that the center of the membrane is `z=0` and extracellular
91-
is positive.
91+
is positive. Moreover, the mean `x` and `y` position of atoms in the
92+
transmembrane residues will be zero.
9293
9394
The algorithm finds the membrane normal `u` by maximizing the ratio
9495
95-
sumᵢ (u ⋅ vᵢ)²
96-
-----------------
97-
sumᵢ (u ⋅ δᵢ)²
96+
Σᵢ (u ⋅ vᵢ)²
97+
------------
98+
Σᵢ (u ⋅ δᵢ)²
9899
99100
where `vᵢ` is a vector parallel to the `i`th TM helix, and `δᵢ` is a
100101
within-leaflet atomic displacement.
@@ -111,8 +112,8 @@ function align_to_membrane(chain::ChainLike, tms; extracellular::Bool=true)
111112
# Collect the atom displacements in each leaflet
112113
delta_e = leaflet_displacements(leaflet_e)
113114
delta_i = leaflet_displacements(leaflet_i)
114-
# Also collect the vectors for the TM helices
115-
tm_vectors = [residue_centroid(chain[first(r)]) - residue_centroid(chain[last(r)]) for r in tms]
115+
# Also collect the vectors for the TM helices. Use the CA atoms since these are part of the backbone.
116+
tm_vectors = [coords(chain[first(r)]["CA"]) - coords(chain[last(r)]["CA"]) for r in tms]
116117
# Find the membrane normal u, maximizing the ratio
117118
# sumᵢ (u ⋅ vᵢ)²
118119
# -----------------
@@ -133,7 +134,7 @@ function align_to_membrane(chain::ChainLike, tms; extracellular::Bool=true)
133134
t = [0, 0, mean(proj_e) > mean(proj_i) ? 1 : -1] # extracellular is positive
134135
q = QuatRotation(1 + u'*t, cross(u, t)...)
135136
# Apply the rotation to the coordinates, and offset the z-coordinate to the mean of the leaflets
136-
ccoords = coordarray(chain)
137+
ccoords = coordarray(collectresidues(chain)[reduce(vcat, tms)])
137138
μ = vec(mean(ccoords, dims=2))
138139
return Transformation(μ, [0, 0, (median(proj_e) + median(proj_i))/2 - μ'*u], RotMatrix(q))
139140
end

src/features.jl

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,36 @@ function features_from_structure(seq, idxs=1:length(seq); kwargs...)
163163
end
164164
return mgmm
165165
end
166+
167+
"""
168+
mgmm = features_from_structure(seq::ChainLike, ρmax::Real, zi::AbstractInterval)
169+
170+
Construct an `IsotropicMultiGMM` from `seq` including all atoms that lie within
171+
the cylinder
172+
173+
x^2 + y^2 <= ρmax^2
174+
z ∈ zi
175+
176+
`zi` is an `AbstractInterval`, e.g. `0..30` or `-15..15` (see IntervalSets.jl).
177+
178+
This implicitly assumes that you've aligned `seq` to the membrane, or aligned
179+
`seq` to a homolog that is membrane-aligned. See [`align_to_membrane`](@ref),
180+
[`align`](@ref).
181+
"""
182+
function features_from_structure(
183+
seq, ρmax::Real, zi::AbstractInterval;
184+
σfun = atomic_σfun,
185+
ϕfun = atomic_ϕfun,
186+
)
187+
mgmm = IsotropicMultiGMM(Dict{Symbol,IsotropicGMM{3,Float64}}())
188+
for r in seq
189+
for a in r
190+
c = coords(a)
191+
ρ = hypot(c[1], c[2])
192+
if ρ < ρmax && c[3] zi
193+
add_features_from_atom!(mgmm, a, r, σfun, ϕfun)
194+
end
195+
end
196+
end
197+
return mgmm
198+
end

test/runtests.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ using BioStructures
99
using FASTX
1010
using GaussianMixtureAlignment
1111
using InvertedIndices
12+
using IntervalSets
1213
using Statistics
1314
using LinearAlgebra
1415
using JuMP, HiGHS
@@ -240,6 +241,8 @@ using Test
240241
zi = median(ci[3,:])
241242
@test ze > zi # extracellular is positive
242243
@test abs(ze + zi) < 1e-6 * (ze - zi) # center of membrane is at z=0
244+
ccoords = coordarray(collectresidues(opsd)[reduce(vcat, opsd_tms)])
245+
@test norm(mean(ccoords, dims=2)[1:2]) < 1000 * eps(eltype(ccoords)) # mean x and y is zero
243246

244247
tm_res = inward_tm_residues(opsd, opsd_tms[[2,3,5,6,7]])
245248
@test length(tm_res) == 5
@@ -285,6 +288,14 @@ using Test
285288
@test g1.ϕ >= g2.ϕ
286289
end
287290
end
291+
292+
cyl_mgmm = features_from_structure(opsd, 12, 0 .. 8)
293+
for (k, gmm) in cyl_mgmm
294+
for g in gmm
295+
@test g.μ[1]^2 + g.μ[2]^2 <= 12^2
296+
@test g.μ[3] 0 .. 8
297+
end
298+
end
288299
end
289300

290301
@testset "Forces" begin

0 commit comments

Comments
 (0)