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

src/parser/psf-parser.js

/**
 * @file Psf Parser
 * @author Alexander Rose <alexander.rose@weirdbyte.de>
 * @private
 */

import { Debug, Log, ParserRegistry } from '../globals.js'
import StructureParser from './structure-parser.js'
import {
  assignResidueTypeBonds, calculateBondsBetween,
  calculateBondsWithin, getChainname
} from '../structure/structure-utils.js'

const TitleMode = 1
const AtomMode = 2
const BondMode = 3
const AngleMode = 4
const DihedralMode = 5
const ImproperMode = 6

const reWhitespace = /\s+/
const reTitle = /(^\*|REMARK)*/

class PsfParser extends StructureParser {
  get type () { return 'psf' }

  _parse () {
    // http://www.ks.uiuc.edu/Training/Tutorials/namd/namd-tutorial-unix-html/node23.html

    if (Debug) Log.time('PsfParser._parse ' + this.name)

    const s = this.structure
    const sb = this.structureBuilder

    //

    const atomMap = s.atomMap
    const atomStore = s.atomStore
    atomStore.addField('partialCharge', 1, 'float32')

    const title = []

    let mode
    let chainid
    let lastSegid
    let idx = 0
    let chainIdx = 0
    let bondIdx = 0
    let bAtomIndex1, bAtomIndex2, bBondOrder

    function _parseChunkOfLines (_i, _n, lines) {
      for (let i = _i; i < _n; ++i) {
        const line = lines[ i ].trim()

        if (!line) {
          mode = undefined
          continue
        }

        if (mode === AtomMode) {
          const ls = line.split(reWhitespace)

          const serial = parseInt(ls[ 0 ])
          const segid = ls[ 1 ]
          const resno = parseInt(ls[ 2 ])
          const resname = ls[ 3 ]
          const atomname = ls[ 4 ]
          const charge = parseFloat(ls[ 6 ])

          if (segid !== lastSegid) {
            chainid = getChainname(chainIdx)
            ++chainIdx
          }

          atomStore.growIfFull()
          atomStore.atomTypeId[ idx ] = atomMap.add(atomname)

          atomStore.serial[ idx ] = serial
          atomStore.partialCharge[ idx ] = charge

          sb.addAtom(0, chainid, chainid, resname, resno)

          idx += 1
          lastSegid = segid
        } else if (mode === BondMode) {
          const ls = line.split(reWhitespace)

          for (let j = 0, m = ls.length; j < m; j += 2) {
            bAtomIndex1[ bondIdx ] = parseInt(ls[ j ]) - 1
            bAtomIndex2[ bondIdx ] = parseInt(ls[ j + 1 ]) - 1
            bBondOrder[ bondIdx ] = 1
            bondIdx += 1
          }
        } else if (mode === TitleMode) {
          title.push(line.replace(reTitle, '').trim())
        } else if (mode === AngleMode) {

          // currently not used

        } else if (mode === DihedralMode) {

          // currently not used

        } else if (mode === ImproperMode) {

          // currently not used

        } else if (line.includes('!NATOM')) {
          mode = AtomMode

          const numAtoms = parseInt(line.split(reWhitespace)[ 0 ])
          atomStore.resize(numAtoms)
        } else if (line.includes('!NBOND')) {
          mode = BondMode

          const numBonds = parseInt(line.split(reWhitespace)[ 0 ])
          bAtomIndex1 = new Uint32Array(numBonds)
          bAtomIndex2 = new Uint32Array(numBonds)
          bBondOrder = new Uint8Array(numBonds)
        } else if (line.includes('!NTITLE')) {
          mode = TitleMode
        } else if (line.includes('!NTHETA')) {
          mode = AngleMode
        } else if (line.includes('!NPHI')) {
          mode = DihedralMode
        } else if (line.includes('!NIMPHI')) {
          mode = ImproperMode
        }
      }
    }

    this.streamer.eachChunkOfLines(function (lines/*, chunkNo, chunkCount */) {
      _parseChunkOfLines(0, lines.length, lines)
    })

    s.title = title.join(' ')

    s.bondStore.length = bBondOrder.length
    s.bondStore.count = bondIdx
    s.bondStore.atomIndex1 = bAtomIndex1
    s.bondStore.atomIndex2 = bAtomIndex2
    s.bondStore.bondOrder = bBondOrder

    sb.finalize()
    s.finalizeAtoms()
    s.finalizeBonds()
    calculateBondsWithin(s, true)
    calculateBondsBetween(s, true, true)
    assignResidueTypeBonds(s)

    if (Debug) Log.timeEnd('PsfParser._parse ' + this.name)
  }
}

ParserRegistry.add('psf', PsfParser)

export default PsfParser