polymer.ts 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. */
  6. import { Unit, Element, StructureProperties, Model } from 'mol-model/structure';
  7. import { Segmentation, Interval } from 'mol-data/int';
  8. import { MoleculeType } from 'mol-model/structure/model/types';
  9. import Iterator from 'mol-data/iterator';
  10. import { SegmentIterator } from 'mol-data/int/impl/segmentation';
  11. import { Vec3 } from 'mol-math/linear-algebra';
  12. import { SymmetryOperator } from 'mol-math/geometry';
  13. // type TraceMap = Map<number, number>
  14. // interface TraceMaps {
  15. // atomic: TraceMap
  16. // spheres: TraceMap
  17. // gaussians: TraceMap
  18. // }
  19. // function calculateTraceMaps (model: Model): TraceMaps {
  20. // }
  21. export function getPolymerElementCount(unit: Unit) {
  22. let count = 0
  23. const { elements } = unit
  24. const l = Element.Location(unit)
  25. if (Unit.isAtomic(unit)) {
  26. const { polymerSegments, residueSegments } = unit.model.atomicHierarchy
  27. const polymerIt = Segmentation.transientSegments(polymerSegments, elements);
  28. const residuesIt = Segmentation.transientSegments(residueSegments, elements);
  29. while (polymerIt.hasNext) {
  30. residuesIt.setSegment(polymerIt.move());
  31. while (residuesIt.hasNext) {
  32. residuesIt.move();
  33. count++
  34. }
  35. }
  36. } else if (Unit.isSpheres(unit)) {
  37. for (let i = 0, il = elements.length; i < il; ++i) {
  38. l.element = elements[i]
  39. if (StructureProperties.entity.type(l) === 'polymer') count++
  40. }
  41. }
  42. return count
  43. }
  44. function getTraceName(l: Element.Location) {
  45. const compId = StructureProperties.residue.label_comp_id(l)
  46. const chemCompMap = l.unit.model.properties.chemicalComponentMap
  47. const cc = chemCompMap.get(compId)
  48. const moleculeType = cc ? cc.moleculeType : MoleculeType.unknown
  49. let traceName = ''
  50. if (moleculeType === MoleculeType.protein) {
  51. traceName = 'CA'
  52. } else if (moleculeType === MoleculeType.DNA || moleculeType === MoleculeType.RNA) {
  53. traceName = 'P'
  54. }
  55. return traceName
  56. }
  57. function setTraceElement(l: Element.Location, residueSegment: Segmentation.Segment<Element>) {
  58. const elements = l.unit.elements
  59. l.element = elements[residueSegment.start]
  60. const traceName = getTraceName(l)
  61. for (let j = residueSegment.start, _j = residueSegment.end; j < _j; j++) {
  62. l.element = elements[j];
  63. if (StructureProperties.atom.label_atom_id(l) === traceName) return j
  64. }
  65. return residueSegment.end - 1
  66. }
  67. function getTraceName2(model: Model, residueModelIndex: number) {
  68. const compId = model.atomicHierarchy.residues.label_comp_id.value(residueModelIndex)
  69. const chemCompMap = model.properties.chemicalComponentMap
  70. const cc = chemCompMap.get(compId)
  71. const moleculeType = cc ? cc.moleculeType : MoleculeType.unknown
  72. let traceName = ''
  73. if (moleculeType === MoleculeType.protein) {
  74. traceName = 'CA'
  75. } else if (moleculeType === MoleculeType.DNA) {
  76. // traceName = 'P'
  77. traceName = 'C3\''
  78. } else if (moleculeType === MoleculeType.RNA) {
  79. // traceName = 'P'
  80. traceName = 'C4\''
  81. }
  82. return traceName
  83. }
  84. function getTraceElement2(model: Model, residueModelSegment: Segmentation.Segment<Element>) {
  85. const traceName = getTraceName2(model, residueModelSegment.index)
  86. for (let j = residueModelSegment.start, _j = residueModelSegment.end; j < _j; j++) {
  87. if (model.atomicHierarchy.atoms.label_atom_id.value(j) === traceName) return j
  88. }
  89. console.log('trace name element not found', { ...residueModelSegment })
  90. return residueModelSegment.start
  91. }
  92. function getDirectionName2(model: Model, residueModelIndex: number) {
  93. const compId = model.atomicHierarchy.residues.label_comp_id.value(residueModelIndex)
  94. const chemCompMap = model.properties.chemicalComponentMap
  95. const cc = chemCompMap.get(compId)
  96. const moleculeType = cc ? cc.moleculeType : MoleculeType.unknown
  97. let traceName = ''
  98. if (moleculeType === MoleculeType.protein) {
  99. traceName = 'O'
  100. } else if (moleculeType === MoleculeType.DNA) {
  101. traceName = 'O4\''
  102. } else if (moleculeType === MoleculeType.RNA) {
  103. traceName = 'C3\''
  104. }
  105. return traceName
  106. }
  107. function getDirectionElement2(model: Model, residueModelSegment: Segmentation.Segment<Element>) {
  108. const traceName = getDirectionName2(model, residueModelSegment.index)
  109. for (let j = residueModelSegment.start, _j = residueModelSegment.end; j < _j; j++) {
  110. if (model.atomicHierarchy.atoms.label_atom_id.value(j) === traceName) return j
  111. }
  112. console.log('direction name element not found', { ...residueModelSegment })
  113. return residueModelSegment.start
  114. }
  115. /** Iterates over consecutive pairs of residues/coarse elements in polymers */
  116. export function PolymerBackboneIterator(unit: Unit): Iterator<PolymerBackbonePair> {
  117. switch (unit.kind) {
  118. case Unit.Kind.Atomic: return new AtomicPolymerBackboneIterator(unit)
  119. case Unit.Kind.Spheres:
  120. case Unit.Kind.Gaussians:
  121. return new CoarsePolymerBackboneIterator(unit)
  122. }
  123. }
  124. interface PolymerBackbonePair {
  125. centerA: Element.Location
  126. centerB: Element.Location
  127. indexA: number
  128. indexB: number
  129. posA: Vec3
  130. posB: Vec3
  131. }
  132. function createPolymerBackbonePair (unit: Unit) {
  133. return {
  134. centerA: Element.Location(unit),
  135. centerB: Element.Location(unit),
  136. indexA: 0,
  137. indexB: 0,
  138. posA: Vec3.zero(),
  139. posB: Vec3.zero()
  140. }
  141. }
  142. const enum AtomicPolymerBackboneIteratorState { nextPolymer, firstResidue, nextResidue }
  143. export class AtomicPolymerBackboneIterator<T extends number = number> implements Iterator<PolymerBackbonePair> {
  144. private value: PolymerBackbonePair
  145. private polymerIt: SegmentIterator<Element>
  146. private residueIt: SegmentIterator<Element>
  147. private polymerSegment: Segmentation.Segment<Element>
  148. private state: AtomicPolymerBackboneIteratorState = AtomicPolymerBackboneIteratorState.nextPolymer
  149. private pos: SymmetryOperator.CoordinateMapper
  150. hasNext: boolean = false;
  151. move() {
  152. const { residueIt, polymerIt, value, pos } = this
  153. if (this.state === AtomicPolymerBackboneIteratorState.nextPolymer) {
  154. if (polymerIt.hasNext) {
  155. this.polymerSegment = polymerIt.move();
  156. residueIt.setSegment(this.polymerSegment);
  157. this.state = AtomicPolymerBackboneIteratorState.firstResidue
  158. }
  159. }
  160. if (this.state === AtomicPolymerBackboneIteratorState.firstResidue) {
  161. const residueSegment = residueIt.move();
  162. if (residueIt.hasNext) {
  163. value.indexB = setTraceElement(value.centerB, residueSegment)
  164. pos(value.centerB.element, value.posB)
  165. this.state = AtomicPolymerBackboneIteratorState.nextResidue
  166. } else {
  167. this.state = AtomicPolymerBackboneIteratorState.nextPolymer
  168. }
  169. }
  170. if (this.state === AtomicPolymerBackboneIteratorState.nextResidue) {
  171. const residueSegment = residueIt.move();
  172. value.centerA.element = value.centerB.element
  173. value.indexA = value.indexB
  174. Vec3.copy(value.posA, value.posB)
  175. value.indexB = setTraceElement(value.centerB, residueSegment)
  176. pos(value.centerB.element, value.posB)
  177. if (!residueIt.hasNext) {
  178. this.state = AtomicPolymerBackboneIteratorState.nextPolymer
  179. }
  180. }
  181. this.hasNext = residueIt.hasNext || polymerIt.hasNext
  182. return this.value;
  183. }
  184. constructor(unit: Unit.Atomic) {
  185. const { polymerSegments, residueSegments } = unit.model.atomicHierarchy
  186. this.polymerIt = Segmentation.transientSegments(polymerSegments, unit.elements);
  187. this.residueIt = Segmentation.transientSegments(residueSegments, unit.elements);
  188. this.pos = unit.conformation.invariantPosition
  189. this.value = createPolymerBackbonePair(unit)
  190. this.hasNext = this.residueIt.hasNext || this.polymerIt.hasNext
  191. }
  192. }
  193. const enum CoarsePolymerBackboneIteratorState { nextPolymer, firstElement, nextElement }
  194. export class CoarsePolymerBackboneIterator<T extends number = number> implements Iterator<PolymerBackbonePair> {
  195. private value: PolymerBackbonePair
  196. private polymerIt: SegmentIterator<Element>
  197. private polymerSegment: Segmentation.Segment<Element>
  198. private state: CoarsePolymerBackboneIteratorState = CoarsePolymerBackboneIteratorState.nextPolymer
  199. private pos: SymmetryOperator.CoordinateMapper
  200. private elementIndex: number
  201. hasNext: boolean = false;
  202. move() {
  203. const { polymerIt, value, pos } = this
  204. if (this.state === CoarsePolymerBackboneIteratorState.nextPolymer) {
  205. if (polymerIt.hasNext) {
  206. this.polymerSegment = polymerIt.move();
  207. this.elementIndex = this.polymerSegment.start
  208. this.state = CoarsePolymerBackboneIteratorState.firstElement
  209. }
  210. }
  211. if (this.state === CoarsePolymerBackboneIteratorState.firstElement) {
  212. this.elementIndex += 1
  213. if (this.elementIndex + 1 < this.polymerSegment.end) {
  214. value.centerB.element = value.centerB.unit.elements[this.elementIndex]
  215. value.indexB = this.elementIndex
  216. pos(value.centerB.element, value.posB)
  217. this.state = CoarsePolymerBackboneIteratorState.nextElement
  218. } else {
  219. this.state = CoarsePolymerBackboneIteratorState.nextPolymer
  220. }
  221. }
  222. if (this.state === CoarsePolymerBackboneIteratorState.nextElement) {
  223. this.elementIndex += 1
  224. value.centerA.element = value.centerB.element
  225. value.indexA = value.indexB
  226. Vec3.copy(value.posA, value.posB)
  227. value.centerB.element = value.centerB.unit.elements[this.elementIndex]
  228. value.indexB = this.elementIndex
  229. pos(value.centerB.element, value.posB)
  230. if (this.elementIndex + 1 >= this.polymerSegment.end) {
  231. this.state = CoarsePolymerBackboneIteratorState.nextPolymer
  232. }
  233. }
  234. this.hasNext = this.elementIndex + 1 < this.polymerSegment.end || polymerIt.hasNext
  235. return this.value;
  236. }
  237. constructor(unit: Unit.Spheres | Unit.Gaussians) {
  238. const { polymerSegments } = Unit.isSpheres(unit)
  239. ? unit.model.coarseHierarchy.spheres
  240. : unit.model.coarseHierarchy.gaussians
  241. this.polymerIt = Segmentation.transientSegments(polymerSegments, unit.elements);
  242. this.pos = unit.conformation.invariantPosition
  243. this.value = createPolymerBackbonePair(unit)
  244. this.hasNext = this.polymerIt.hasNext
  245. }
  246. }
  247. /**
  248. * Iterates over individual residues/coarse elements in polymers of a unit while
  249. * providing information about the neighbourhood in the underlying model for drawing splines
  250. */
  251. export function PolymerTraceIterator(unit: Unit): Iterator<PolymerTraceElement> {
  252. switch (unit.kind) {
  253. case Unit.Kind.Atomic: return new AtomicPolymerTraceIterator(unit)
  254. case Unit.Kind.Spheres:
  255. case Unit.Kind.Gaussians:
  256. return new CoarsePolymerTraceIterator(unit)
  257. }
  258. }
  259. interface PolymerTraceElement {
  260. center: Element.Location
  261. index: number
  262. first: boolean
  263. last: boolean
  264. t0: Vec3
  265. t1: Vec3
  266. t2: Vec3
  267. t3: Vec3
  268. t4: Vec3
  269. t5: Vec3
  270. t6: Vec3
  271. d12: Vec3
  272. d23: Vec3
  273. d34: Vec3
  274. d45: Vec3
  275. }
  276. function createPolymerTraceElement (unit: Unit): PolymerTraceElement {
  277. return {
  278. center: Element.Location(unit),
  279. index: 0,
  280. first: false,
  281. last: false,
  282. t0: Vec3.zero(),
  283. t1: Vec3.zero(),
  284. t2: Vec3.zero(),
  285. t3: Vec3.zero(),
  286. t4: Vec3.zero(),
  287. t5: Vec3.zero(),
  288. t6: Vec3.zero(),
  289. d12: Vec3.zero(),
  290. d23: Vec3.zero(),
  291. d34: Vec3.zero(),
  292. d45: Vec3.zero(),
  293. }
  294. }
  295. const enum AtomicPolymerTraceIteratorState { nextPolymer, nextResidue }
  296. function setSegment (outSegment: Segmentation.Segment<Element>, index: number, segments: Segmentation<Element>, min: number, max: number): Segmentation.Segment<Element> {
  297. // index = Math.min(Math.max(0, index), segments.segments.length - 2)
  298. const _index = Math.min(Math.max(min, index), max)
  299. if (isNaN(_index)) console.log(_index, index, min, max)
  300. outSegment.index = _index
  301. outSegment.start = segments.segments[_index]
  302. outSegment.end = segments.segments[_index + 1]
  303. // console.log(index, {...outSegment}, {...boundingSegment}, segments.segments[boundingSegment.index])
  304. return outSegment
  305. }
  306. export class AtomicPolymerTraceIterator<T extends number = number> implements Iterator<PolymerTraceElement> {
  307. private value: PolymerTraceElement
  308. private polymerIt: SegmentIterator<Element>
  309. private residueIt: SegmentIterator<Element>
  310. private residueSegmentMin: number
  311. private residueSegmentMax: number
  312. private state: AtomicPolymerTraceIteratorState = AtomicPolymerTraceIteratorState.nextPolymer
  313. private residueSegments: Segmentation<Element>
  314. private tmpSegment: Segmentation.Segment<Element>
  315. private unit: Unit.Atomic
  316. hasNext: boolean = false;
  317. private pos(target: Vec3, index: number) {
  318. target[0] = this.unit.model.atomicConformation.x[index]
  319. target[1] = this.unit.model.atomicConformation.y[index]
  320. target[2] = this.unit.model.atomicConformation.z[index]
  321. }
  322. updateResidueSegmentRange(polymerSegment: Segmentation.Segment<Element>) {
  323. const { polymerSegments, residueSegments } = this.unit.model.atomicHierarchy
  324. const sMin = polymerSegments.segments[polymerSegment.index]
  325. const sMax = polymerSegments.segments[polymerSegment.index + 1] - 1
  326. this.residueSegmentMin = residueSegments.segmentMap[sMin]
  327. this.residueSegmentMax = residueSegments.segmentMap[sMax]
  328. }
  329. move() {
  330. const { residueIt, polymerIt, value } = this
  331. if (this.state === AtomicPolymerTraceIteratorState.nextPolymer) {
  332. if (polymerIt.hasNext) {
  333. const polymerSegment = polymerIt.move();
  334. residueIt.setSegment(polymerSegment);
  335. this.updateResidueSegmentRange(polymerSegment)
  336. this.state = AtomicPolymerTraceIteratorState.nextResidue
  337. }
  338. }
  339. if (this.state === AtomicPolymerTraceIteratorState.nextResidue) {
  340. const { tmpSegment, residueSegments, residueSegmentMin, residueSegmentMax } = this
  341. const residueSegment = residueIt.move();
  342. const resSegIdx = residueSegment.index
  343. value.index = setTraceElement(value.center, residueSegment)
  344. setSegment(tmpSegment, resSegIdx - 3, residueSegments, residueSegmentMin, residueSegmentMax)
  345. this.pos(value.t0, getTraceElement2(this.unit.model, tmpSegment))
  346. setSegment(tmpSegment, resSegIdx - 2, residueSegments, residueSegmentMin, residueSegmentMax)
  347. this.pos(value.t1, getTraceElement2(this.unit.model, tmpSegment))
  348. this.pos(value.d12, getDirectionElement2(this.unit.model, tmpSegment))
  349. setSegment(tmpSegment, resSegIdx - 1, residueSegments, residueSegmentMin, residueSegmentMax)
  350. this.pos(value.t2, getTraceElement2(this.unit.model, tmpSegment))
  351. this.pos(value.d23, getDirectionElement2(this.unit.model, tmpSegment))
  352. setSegment(tmpSegment, resSegIdx, residueSegments, residueSegmentMin, residueSegmentMax)
  353. this.pos(value.t3, getTraceElement2(this.unit.model, tmpSegment))
  354. this.pos(value.d34, getDirectionElement2(this.unit.model, tmpSegment))
  355. setSegment(tmpSegment, resSegIdx + 1, residueSegments, residueSegmentMin, residueSegmentMax)
  356. this.pos(value.t4, getTraceElement2(this.unit.model, tmpSegment))
  357. this.pos(value.d45, getDirectionElement2(this.unit.model, tmpSegment))
  358. setSegment(tmpSegment, resSegIdx + 2, residueSegments, residueSegmentMin, residueSegmentMax)
  359. this.pos(value.t5, getTraceElement2(this.unit.model, tmpSegment))
  360. setSegment(tmpSegment, resSegIdx + 3, residueSegments, residueSegmentMin, residueSegmentMax)
  361. this.pos(value.t6, getTraceElement2(this.unit.model, tmpSegment))
  362. value.first = resSegIdx === residueSegmentMin
  363. value.last = resSegIdx === residueSegmentMax
  364. if (!residueIt.hasNext) {
  365. this.state = AtomicPolymerTraceIteratorState.nextPolymer
  366. }
  367. }
  368. this.hasNext = residueIt.hasNext || polymerIt.hasNext
  369. return this.value;
  370. }
  371. constructor(unit: Unit.Atomic) {
  372. const { polymerSegments, residueSegments } = unit.model.atomicHierarchy
  373. this.polymerIt = Segmentation.transientSegments(polymerSegments, unit.elements);
  374. this.residueIt = Segmentation.transientSegments(residueSegments, unit.elements);
  375. this.residueSegments = residueSegments
  376. this.value = createPolymerTraceElement(unit)
  377. this.hasNext = this.residueIt.hasNext || this.polymerIt.hasNext
  378. this.tmpSegment = { index: 0, start: 0 as Element, end: 0 as Element }
  379. this.unit = unit
  380. console.log('model', unit.model)
  381. console.log('unit', unit)
  382. }
  383. }
  384. export class CoarsePolymerTraceIterator<T extends number = number> implements Iterator<PolymerTraceElement> {
  385. private value: PolymerTraceElement
  386. hasNext: boolean = false;
  387. move() {
  388. return this.value;
  389. }
  390. constructor(unit: Unit.Spheres | Unit.Gaussians) {
  391. this.value = createPolymerTraceElement(unit)
  392. this.hasNext = false
  393. }
  394. }