NGL@1.0.0-beta.7 Home Manual Reference Source Gallery

src/parser/mol2-parser.js

  1. /**
  2. * @file Mol2 Parser
  3. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  4. * @private
  5. */
  6.  
  7. import { Debug, Log, ParserRegistry } from '../globals.js'
  8. import {
  9. assignResidueTypeBonds,
  10. calculateChainnames, calculateSecondaryStructure,
  11. calculateBondsBetween, calculateBondsWithin
  12. } from '../structure/structure-utils.js'
  13. import StructureParser from './structure-parser.js'
  14.  
  15. const reWhitespace = /\s+/
  16. const bondTypes = {
  17. '1': 1,
  18. '2': 2,
  19. '3': 3,
  20. 'am': 1, // amide
  21. 'ar': 1, // aromatic
  22. 'du': 1, // dummy
  23. 'un': 1, // unknown
  24. 'nc': 0 // not connected
  25. }
  26.  
  27. class Mol2Parser extends StructureParser {
  28. get type () { return 'mol2' }
  29.  
  30. _parse () {
  31. // http://paulbourke.net/dataformats/mol2/
  32.  
  33. if (Debug) Log.time('Mol2Parser._parse ' + this.name)
  34.  
  35. const s = this.structure
  36. const sb = this.structureBuilder
  37.  
  38. const firstModelOnly = this.firstModelOnly
  39. const asTrajectory = this.asTrajectory
  40.  
  41. const frames = s.frames
  42. let doFrames = false
  43. let currentFrame, currentCoord
  44.  
  45. const atomMap = s.atomMap
  46. const atomStore = s.atomStore
  47. atomStore.resize(Math.round(this.streamer.data.length / 60))
  48. atomStore.addField('partialCharge', 1, 'float32')
  49.  
  50. let idx = 0
  51. let moleculeLineNo = 0
  52. let modelAtomIdxStart = 0
  53. let modelIdx = -1
  54. let numAtoms = 0
  55.  
  56. let currentRecordType = 0
  57. let moleculeRecordType = 1
  58. let atomRecordType = 2
  59. let bondRecordType = 3
  60.  
  61. const ap1 = s.getAtomProxy()
  62. const ap2 = s.getAtomProxy()
  63.  
  64. function _parseChunkOfLines (_i, _n, lines) {
  65. for (let i = _i; i < _n; ++i) {
  66. const line = lines[ i ].trim()
  67.  
  68. if (line === '' || line[ 0 ] === '#') continue
  69.  
  70. if (line[ 0 ] === '@') {
  71. if (line === '@<TRIPOS>MOLECULE') {
  72. currentRecordType = moleculeRecordType
  73. moleculeLineNo = 0
  74.  
  75. ++modelIdx
  76. } else if (line === '@<TRIPOS>ATOM') {
  77. currentRecordType = atomRecordType
  78. modelAtomIdxStart = atomStore.count
  79.  
  80. if (asTrajectory) {
  81. currentCoord = 0
  82. currentFrame = new Float32Array(numAtoms * 3)
  83. frames.push(currentFrame)
  84.  
  85. if (modelIdx > 0) doFrames = true
  86. }
  87. } else if (line === '@<TRIPOS>BOND') {
  88. currentRecordType = bondRecordType
  89. } else {
  90. currentRecordType = 0
  91. }
  92. } else if (currentRecordType === moleculeRecordType) {
  93. if (moleculeLineNo === 0) {
  94. s.title = line
  95. s.id = line
  96. } else if (moleculeLineNo === 1) {
  97. const ls = line.split(reWhitespace)
  98. numAtoms = parseInt(ls[ 0 ])
  99. // num_atoms [num_bonds [num_subst [num_feat [num_sets]]]]
  100. } else if (moleculeLineNo === 2) {
  101.  
  102. // const molType = line;
  103. // SMALL, BIOPOLYMER, PROTEIN, NUCLEIC_ACID, SACCHARIDE
  104.  
  105. } else if (moleculeLineNo === 3) {
  106.  
  107. // const chargeType = line;
  108. // NO_CHARGES, DEL_RE, GASTEIGER, GAST_HUCK, HUCKEL,
  109. // PULLMAN, GAUSS80_CHARGES, AMPAC_CHARGES,
  110. // MULLIKEN_CHARGES, DICT_ CHARGES, MMFF94_CHARGES,
  111. // USER_CHARGES
  112.  
  113. } else if (moleculeLineNo === 4) {
  114.  
  115. // const statusBits = line;
  116.  
  117. } else if (moleculeLineNo === 5) {
  118.  
  119. // const molComment = line;
  120.  
  121. }
  122.  
  123. ++moleculeLineNo
  124. } else if (currentRecordType === atomRecordType) {
  125. const ls = line.split(reWhitespace)
  126.  
  127. if (firstModelOnly && modelIdx > 0) continue
  128.  
  129. const x = parseFloat(ls[ 2 ])
  130. const y = parseFloat(ls[ 3 ])
  131. const z = parseFloat(ls[ 4 ])
  132.  
  133. if (asTrajectory) {
  134. const j = currentCoord * 3
  135.  
  136. currentFrame[ j + 0 ] = x
  137. currentFrame[ j + 1 ] = y
  138. currentFrame[ j + 2 ] = z
  139.  
  140. currentCoord += 1
  141.  
  142. if (doFrames) continue
  143. }
  144.  
  145. const serial = ls[ 0 ]
  146. const atomname = ls[ 1 ]
  147. const element = ls[ 5 ].split('.')[ 0 ]
  148. const resno = ls[ 6 ] ? parseInt(ls[ 6 ]) : 1
  149. const resname = ls[ 7 ] ? ls[ 7 ] : ''
  150. const partialCharge = ls[ 8 ] ? parseFloat(ls[ 8 ]) : 0.0
  151.  
  152. atomStore.growIfFull()
  153. atomStore.atomTypeId[ idx ] = atomMap.add(atomname, element)
  154.  
  155. atomStore.x[ idx ] = x
  156. atomStore.y[ idx ] = y
  157. atomStore.z[ idx ] = z
  158. atomStore.serial[ idx ] = serial
  159. atomStore.partialCharge[ idx ] = partialCharge
  160.  
  161. sb.addAtom(modelIdx, '', '', resname, resno, 1)
  162.  
  163. idx += 1
  164. } else if (currentRecordType === bondRecordType) {
  165. if (firstModelOnly && modelIdx > 0) continue
  166. if (asTrajectory && modelIdx > 0) continue
  167.  
  168. const ls = line.split(reWhitespace)
  169.  
  170. // ls[ 0 ] is bond id
  171. ap1.index = parseInt(ls[ 1 ]) - 1 + modelAtomIdxStart
  172. ap2.index = parseInt(ls[ 2 ]) - 1 + modelAtomIdxStart
  173. const order = bondTypes[ ls[ 3 ] ]
  174.  
  175. s.bondStore.addBond(ap1, ap2, order)
  176. }
  177. }
  178. }
  179.  
  180. this.streamer.eachChunkOfLines(function (lines/*, chunkNo, chunkCount */) {
  181. _parseChunkOfLines(0, lines.length, lines)
  182. })
  183.  
  184. sb.finalize()
  185. s.finalizeAtoms()
  186. calculateChainnames(s)
  187. calculateBondsWithin(s, true)
  188. calculateBondsBetween(s, true)
  189. s.finalizeBonds()
  190. assignResidueTypeBonds(s)
  191. calculateSecondaryStructure(s)
  192.  
  193. if (Debug) Log.timeEnd('Mol2Parser._parse ' + this.name)
  194. }
  195. }
  196.  
  197. ParserRegistry.add('mol2', Mol2Parser)
  198.  
  199. export default Mol2Parser