Skip to content

Commit

Permalink
Allow chain id to be assigned with chainid!()
Browse files Browse the repository at this point in the history
Adds two function for assigning the chainid, chainid!(chain, new_id) and
chainid!(residue, new_id). For GitHub issue BioJulia#22.
  • Loading branch information
gusennan committed Oct 21, 2021
1 parent d1fc832 commit 7b1dd1b
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 4 deletions.
51 changes: 47 additions & 4 deletions src/model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export
resnames,
chain,
chainid,
chainid!,
resids,
residues,
model,
Expand Down Expand Up @@ -127,7 +128,7 @@ A residue (amino acid) or other molecule - either a `Residue` or a
abstract type AbstractResidue <: StructuralElement end

"A residue (amino acid) or other molecule."
struct Residue <: AbstractResidue
mutable struct Residue <: AbstractResidue
name::String
number::Int
ins_code::Char
Expand All @@ -147,7 +148,7 @@ struct DisorderedResidue <: AbstractResidue
end

"A chain (molecule) from a macromolecular structure."
struct Chain <: StructuralElement
mutable struct Chain <: StructuralElement
id::String # mmCIF files can have multi-character chain IDs
res_list::Vector{String}
residues::Dict{String, AbstractResidue}
Expand Down Expand Up @@ -816,6 +817,48 @@ Get the chain ID of an `AbstractAtom`, `AbstractResidue` or `Chain` as a
chainid(el::Union{AbstractResidue, AbstractAtom}) = chainid(chain(el))
chainid(ch::Chain) = ch.id

"""
chainid!(ch, id)
Set the chain ID of an `Chain` to a new `String`.
"""
chainid!(ch::Chain, id::String) = ch.id = id

"""
chainid!(res, id)
Set the chain ID of an `AbstractResidue` to a new `String`.
If a chain with this ID already exists, it will be removed from its current
chain and added to that chain. If a chain with this ID does not exist, a new
chain will be added to the model and this residue will be added to it. If
moving this residue from a chain to a new chain renders the old chain without
residues, the old chain will be removed from the `Model`.
"""
function chainid!(res::AbstractResidue, id::String)
current_chain = res.chain
model_chains = current_chain.model.chains

# find the currently-assigned resid, which may not have been created from the resid function
current_resid = first(filter(el -> el.second == res, current_chain.residues)).first

if id in keys(model_chains)
model_chains[id].residues[resid(res)] = res
else
model_chains[id] = Chain(id, [], Dict(current_resid => res), current_chain.model)
end
res.chain = model_chains[id]

# remove the residue from its current chain
delete!(current_chain.residues, current_resid)
if isempty(current_chain.residues)
delete!(model_chains, current_chain.id)
end

fixlists!(structure(res))
end


"""
resids(ch)
Expand Down Expand Up @@ -1522,7 +1565,7 @@ fullresname(res::Residue) = res.name
function fixlists!(struc::ProteinStructure)
for mod in struc
for ch in mod
append!(ch.res_list, resid.(sort(collect(values(residues(ch))))))
ch.res_list = resid.(sort(collect(values(residues(ch)))))
for res in ch
if isa(res, Residue)
fixlists!(res)
Expand All @@ -1537,7 +1580,7 @@ function fixlists!(struc::ProteinStructure)
end

function fixlists!(res::Residue)
append!(res.atom_list, fullatomname.(sort(collect(values(atoms(res))))))
res.atom_list = fullatomname.(sort(collect(values(atoms(res)))))
end

fullatomname(at::Atom) = at.name
Expand Down
27 changes: 27 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,33 @@ end
@test chainid(dis_res) == "A"
@test chainid(ch) == "A"

# test modifying the chain ids
chainid!(ch, "C")
@test chainid(at) == "C"
@test chainid(dis_at) == "C"
@test chainid(res) == "C"
@test chainid(dis_res) == "C"
@test chainid(ch) == "C"

@test chainids(mod) == ["B", "C"]
chainid!(ch, "A")

# move one of the residues to a new chain and StructuralElements below it
# should identify on the new chain
chainid!(res, "C")
@test chainid(res) == "C"
@test chainid(at) == "C"
@test chainid(dis_at) == "C"
@test chainid(dis_res) == "A"
@test chainid(ch) == "A"

@test chainids(mod) == ["A", "B", "C"]

# Emptying a chain of residues by moving its residues deletes the chain
chainid!(res, "A")

@test chainids(mod) == ["A", "B"]

@test resids(ch) == ["10", "H_20A"]

@test isa(residues(ch), Dict{String, AbstractResidue})
Expand Down

0 comments on commit 7b1dd1b

Please sign in to comment.