|
16 | 16 | omegaangles, |
17 | 17 | phiangles, |
18 | 18 | psiangles, |
| 19 | + chiangle, |
| 20 | + chiangles, |
19 | 21 | ramachandranangles, |
20 | 22 | SpatialMap, |
21 | 23 | ContactMap, |
@@ -341,7 +343,7 @@ function dihedralangle(vec_a::AbstractVector{<:Real}, |
341 | 343 | vec_b::AbstractVector{<:Real}, |
342 | 344 | vec_c::AbstractVector{<:Real}) |
343 | 345 | return atan( |
344 | | - dot(cross(cross(vec_a, vec_b), cross(vec_b, vec_c)), vec_b / norm(vec_b)), |
| 346 | + norm(vec_b) * dot(vec_a, cross(vec_b, vec_c)), |
345 | 347 | dot(cross(vec_a, vec_b), cross(vec_b, vec_c))) |
346 | 348 | end |
347 | 349 |
|
@@ -462,6 +464,126 @@ function psiangle(chain::Chain, res_id::Union{Integer, AbstractString}) |
462 | 464 | return psiangle(chain[resids(chain)[i]], chain[resids(chain)[i + 1]]) |
463 | 465 | end |
464 | 466 |
|
| 467 | +# source: http://www.mlb.co.jp/linux/science/garlic/doc/commands/dihedrals.html |
| 468 | +const chitables = [ |
| 469 | + Dict{String,NTuple{4,String}}( |
| 470 | + "ARG" => ("N", "CA", "CB", "CG"), |
| 471 | + "ASN" => ("N", "CA", "CB", "CG"), |
| 472 | + "ASP" => ("N", "CA", "CB", "CG"), |
| 473 | + "CYS" => ("N", "CA", "CB", "SG"), |
| 474 | + "GLN" => ("N", "CA", "CB", "CG"), |
| 475 | + "GLU" => ("N", "CA", "CB", "CG"), |
| 476 | + "HIS" => ("N", "CA", "CB", "CG"), |
| 477 | + "ILE" => ("N", "CA", "CB", "CG1"), |
| 478 | + "LEU" => ("N", "CA", "CB", "CG"), |
| 479 | + "LYS" => ("N", "CA", "CB", "CG"), |
| 480 | + "MET" => ("N", "CA", "CB", "CG"), |
| 481 | + "PHE" => ("N", "CA", "CB", "CG"), |
| 482 | + "PRO" => ("N", "CA", "CB", "CG"), |
| 483 | + "SER" => ("N", "CA", "CB", "OG"), |
| 484 | + "THR" => ("N", "CA", "CB", "OG1"), |
| 485 | + "TRP" => ("N", "CA", "CB", "CG"), |
| 486 | + "TYR" => ("N", "CA", "CB", "CG"), |
| 487 | + "VAL" => ("N", "CA", "CB", "CG1"), |
| 488 | + ), |
| 489 | + Dict{String,NTuple{4,String}}( |
| 490 | + "ARG" => ("CA", "CB", "CG", "CD"), |
| 491 | + "ASN" => ("CA", "CB", "CG", "OD1"), |
| 492 | + "ASP" => ("CA", "CB", "CG", "OD1"), |
| 493 | + "GLN" => ("CA", "CB", "CG", "CD"), |
| 494 | + "GLU" => ("CA", "CB", "CG", "CD"), |
| 495 | + "HIS" => ("CA", "CB", "CG", "ND1"), |
| 496 | + "ILE" => ("CA", "CB", "CG1", "CD1"), |
| 497 | + "LEU" => ("CA", "CB", "CG", "CD1"), |
| 498 | + "LYS" => ("CA", "CB", "CG", "CD"), |
| 499 | + "MET" => ("CA", "CB", "CG", "SD"), |
| 500 | + "PHE" => ("CA", "CB", "CG", "CD1"), |
| 501 | + "PRO" => ("CA", "CB", "CG", "CD"), |
| 502 | + "TRP" => ("CA", "CB", "CG", "CD1"), |
| 503 | + "TYR" => ("CA", "CB", "CG", "CD1"), |
| 504 | + ), |
| 505 | + Dict{String,NTuple{4,String}}( |
| 506 | + "ARG" => ("CB", "CG", "CD", "NE"), |
| 507 | + "GLN" => ("CB", "CG", "CD", "OE1"), |
| 508 | + "GLU" => ("CB", "CG", "CD", "OE1"), |
| 509 | + "LYS" => ("CB", "CG", "CD", "CE"), |
| 510 | + "MET" => ("CB", "CG", "SD", "CE"), |
| 511 | + ), |
| 512 | + Dict{String,NTuple{4,String}}( |
| 513 | + "ARG" => ("CG", "CD", "NE", "CZ"), |
| 514 | + "LYS" => ("CG", "CD", "CE", "NZ"), |
| 515 | + ), |
| 516 | + Dict{String,NTuple{4,String}}( |
| 517 | + "ARG" => ("CD", "NE", "CZ", "NH1"), |
| 518 | + ), |
| 519 | +] |
| 520 | + |
| 521 | +# source: Jumper et al 2021, Supp. Table 2 |
| 522 | +const chisymmetries = [ |
| 523 | + ("ASP", 2), |
| 524 | + ("GLU", 3), |
| 525 | + ("PHE", 2), |
| 526 | + ("TYR", 2), |
| 527 | +] |
| 528 | + |
| 529 | +function chiangle(a1, a2, a3, a4, sym::Bool) |
| 530 | + χ = dihedralangle(a1, a2, a3, a4) |
| 531 | + if sym && χ < 0 |
| 532 | + χ += π |
| 533 | + end |
| 534 | + return χ |
| 535 | +end |
| 536 | + |
| 537 | +""" |
| 538 | + chiangle(res, i) |
| 539 | +
|
| 540 | +Calculate the χᵢ angle in radians for a standard `AbstractResidue` with standard atom names. |
| 541 | +The angle is in the range -π to π. |
| 542 | +""" |
| 543 | +function chiangle(res::AbstractResidue, i::Integer) |
| 544 | + 1 <= i <= 5 || throw(ArgumentError("χᵢ index `i` must be between 1 and 5")) |
| 545 | + ct = chitables[i] |
| 546 | + rname = resname(res) |
| 547 | + t = get(ct, rname, nothing) |
| 548 | + if t === nothing |
| 549 | + # is it because this isn't a standard residue? |
| 550 | + (rname == "GLY" || rname == "ALA") && throw(ArgumentError("$rname does not have any χ angles")) |
| 551 | + haskey(chitables[1], rname) || throw(ArgumentError("no χ angles are defined for residues with name $rname")) |
| 552 | + # it must be missing specifically for `i` |
| 553 | + j = 1 |
| 554 | + while haskey(chitables[j+1], rname) |
| 555 | + j += 1 |
| 556 | + end |
| 557 | + throw(ArgumentError("χ angle with index $i does not exist for residue $rname (max is $j)")) |
| 558 | + end |
| 559 | + return chiangle(res[t[1]], res[t[2]], res[t[3]], res[t[4]], (rname, i) in chisymmetries) |
| 560 | +end |
| 561 | + |
| 562 | +""" |
| 563 | + chiangles(res) |
| 564 | +
|
| 565 | +Calculate the `Vector` of standard χ angles for a standard `AbstractResidue` with standard atom names. |
| 566 | +The length of the vector ranges from 0 (GLY, ALA) to 5 (ARG). |
| 567 | +The angles are each in the range -π to π. |
| 568 | +""" |
| 569 | +function chiangles(res::AbstractResidue) |
| 570 | + chi = Float64[] |
| 571 | + rname = resname(res) |
| 572 | + for i = 1:5 |
| 573 | + ct = chitables[i] |
| 574 | + t = get(ct, rname, nothing) |
| 575 | + if t === nothing |
| 576 | + if i == 1 |
| 577 | + (rname == "GLY" || rname == "ALA") && break |
| 578 | + throw(ArgumentError("no χ angles are defined for residues with name $rname")) |
| 579 | + end |
| 580 | + break |
| 581 | + end |
| 582 | + push!(chi, chiangle(res[t[1]], res[t[2]], res[t[3]], res[t[4]], (rname, i) in chisymmetries)) |
| 583 | + end |
| 584 | + return chi |
| 585 | +end |
| 586 | + |
465 | 587 | """ |
466 | 588 | omegaangles(element, residue_selectors...) |
467 | 589 |
|
@@ -598,6 +720,17 @@ function ramachandranangles(el::StructuralElementOrList, |
598 | 720 | return phiangles(el, residue_selectors...), psiangles(el, residue_selectors...) |
599 | 721 | end |
600 | 722 |
|
| 723 | +""" |
| 724 | + chiangles(element, residue_selectors...) |
| 725 | +
|
| 726 | +Calculate the `Vector` of standard χ angles for each residue in a `StructuralElementOrList`. |
| 727 | +This returns a `Vector` of `Vector`s, where all angles are in the range -π to π. |
| 728 | +Additional arguments are residue selector functions - only residues that return |
| 729 | +`true` from the functions are retained. |
| 730 | +""" |
| 731 | +chiangles(el::StructuralElementOrList, residue_selectors::Function...) = |
| 732 | + [chiangles(r) for r in collectresidues(el, residue_selectors...)] |
| 733 | + |
601 | 734 | "A map of a structural property, e.g. a `ContactMap` or a `DistanceMap`." |
602 | 735 | abstract type SpatialMap end |
603 | 736 |
|
|
0 commit comments