radii.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Sebastian Bittrich <sebastian.bittrich@rcsb.org>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import { MaxAsa, ShrakeRupleyContext, VdWLookup } from './common';
  8. import { getElementIdx, isHydrogen } from '../../../../mol-model/structure/structure/unit/bonds/common';
  9. import { isPolymer, isNucleic, MoleculeType, ElementSymbol } from '../../../../mol-model/structure/model/types';
  10. import { VdwRadius } from '../../../../mol-model/structure/model/properties/atomic';
  11. import { StructureElement, StructureProperties } from '../../../../mol-model/structure/structure';
  12. import { getElementMoleculeType } from '../../../../mol-model/structure/util';
  13. export function assignRadiusForHeavyAtoms(ctx: ShrakeRupleyContext) {
  14. const { key } = StructureProperties.residue;
  15. const { type_symbol, label_atom_id, label_comp_id } = StructureProperties.atom;
  16. const { structure, atomRadiusType, serialResidueIndex } = ctx;
  17. const l = StructureElement.Location.create(structure);
  18. let prevResidueIdx = 0;
  19. let residueIdx = 0;
  20. let serialResidueIdx = -1;
  21. l.structure = structure;
  22. for (let i = 0, m = 0, il = structure.units.length; i < il; ++i) {
  23. const unit = structure.units[i];
  24. const { elements } = unit;
  25. l.unit = unit;
  26. prevResidueIdx = -1;
  27. for (let j = 0, jl = elements.length; j < jl; ++j) {
  28. const eI = elements[j];
  29. const mj = m + j;
  30. l.element = eI;
  31. residueIdx = key(l);
  32. if (prevResidueIdx !== residueIdx) ++serialResidueIdx;
  33. prevResidueIdx = residueIdx;
  34. const element = type_symbol(l);
  35. const elementIdx = getElementIdx(element);
  36. // skip hydrogen atoms
  37. if (isHydrogen(elementIdx)) {
  38. atomRadiusType[mj] = VdWLookup[0];
  39. serialResidueIndex[mj] = -1;
  40. continue;
  41. }
  42. const atomId = label_atom_id(l);
  43. const moleculeType = getElementMoleculeType(unit, eI);
  44. // skip water and optionally non-polymer groups
  45. if (moleculeType === MoleculeType.Water || (!ctx.nonPolymer && !isPolymer(moleculeType)) || (ctx.traceOnly && ((atomId !== 'CA' && atomId !== 'BB') || !MaxAsa[label_comp_id(l)]))) {
  46. atomRadiusType[mj] = VdWLookup[0];
  47. serialResidueIndex[mj] = -1;
  48. continue;
  49. }
  50. const compId = label_comp_id(l);
  51. if (isNucleic(moleculeType)) {
  52. atomRadiusType[mj] = determineRadiusNucl(atomId, element, compId);
  53. } else if (moleculeType === MoleculeType.Protein) {
  54. atomRadiusType[mj] = determineRadiusAmino(atomId, element, compId);
  55. } else {
  56. atomRadiusType[mj] = handleNonStandardCase(element);
  57. }
  58. serialResidueIndex[mj] = serialResidueIdx;
  59. }
  60. m += elements.length;
  61. }
  62. }
  63. /**
  64. * Gets the van der Waals radius of the given atom following the values defined by Chothia (1976)
  65. * J.Mol.Biol.105,1-14. NOTE: the vdw values defined by the paper assume no Hydrogens and thus "inflates" slightly
  66. * the heavy atoms to account for Hydrogens.
  67. */
  68. function determineRadiusAmino(atomId: string, element: ElementSymbol, compId: string): number {
  69. switch (element) {
  70. case 'O':
  71. return 5;
  72. case 'S':
  73. return 6;
  74. case 'N':
  75. return atomId === 'NZ' ? 4 : 3;
  76. case 'C':
  77. switch (atomId) {
  78. case 'C': case 'CE1': case'CE2': case 'CE3': case 'CH2': case 'CZ': case 'CZ2': case 'CZ3':
  79. return 1;
  80. case 'CA': case 'CB': case 'CE': case 'CG1': case 'CG2':
  81. return 2;
  82. default:
  83. switch (compId) {
  84. case 'PHE': case 'TRP': case 'TYR': case 'HIS': case 'ASP': case 'ASN':
  85. return 1;
  86. case 'PRO': case 'LYS': case 'ARG': case 'MET': case 'ILE': case 'LEU':
  87. return 2;
  88. case 'GLU': case 'GLN':
  89. return atomId === 'CD' ? 1 : 2;
  90. }
  91. }
  92. }
  93. return handleNonStandardCase(element);
  94. }
  95. function determineRadiusNucl(atomId: string, element: ElementSymbol, compId: string): number {
  96. switch (element) {
  97. case 'C': return 7;
  98. case 'N': return 8;
  99. case 'P': return 9;
  100. case 'O': return 5;
  101. }
  102. return handleNonStandardCase(element);
  103. }
  104. function handleNonStandardCase(element: ElementSymbol): number {
  105. const radius = VdwRadius(element);
  106. let index = VdWLookup.indexOf(radius);
  107. if (index === -1) {
  108. // add novel value to lookup array
  109. index = VdWLookup.length;
  110. VdWLookup[index] = radius;
  111. }
  112. return index;
  113. }