All files / src/parsers PQR.ts

78.43% Statements 40/51
68.42% Branches 13/19
100% Functions 1/1
79.16% Lines 38/48

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114                              4x 4x 4x 4x 4x   4x 4066x 4066x   4066x 4x 2x 1x 2x     2x     4062x         3652x 3652x 3652x 3652x 3652x       3652x 3652x 3652x 3652x 3652x 3652x   3652x 3652x           3652x     3652x 3652x 3652x                                         410x                                   4x 5x 5x 4x     4x  
import { assignPDBBonds } from "./utils/assignPDBBonds";
import { computeSecondaryStructure } from "./utils/computeSecondaryStructure";
 
    /**
     * Parse a pqr file from str and create atoms. A pqr file is assumed to be a
     * whitespace delimited PDB with charge and radius fields.
     *
     * @param {string}
     *            str
     * @param {ParserOptionsSpec}
     *            options - noSecondaryStructure (do not compute ss)
    * @category Parsers 
     */
export function PQR(str, options) {
 
      var atoms: any[][] & Record<string, any> = [[]];
      var computeStruct = !options.noSecondaryStructure;
      atoms.modelData = [{symmetries:[]}];
      var serialToIndex: number[] = []; // map from pdb serial to index in atoms
      var lines = str.split(/\r?\n|\r/);
      var line;
      for (let i = 0; i < lines.length; i++) {
          line = lines[i].replace(/^\s*/, ''); // remove indent
          var recordName = line.substr(0, 6);
          
          if (recordName.indexOf("END") == 0) {
              if (options.multimodel) {
                  if (!options.onemol)
                      atoms.push([]);
                  continue;
              }
              else {
                  break;
              }
          }
          else if (recordName == 'ATOM  ' || recordName == 'HETATM') {
              // I would have liked to split based solely on whitespace, but
              // it seems that there is no guarantee that all the fields will
              // be filled out (e.g. the chain) so this doesn't work
              var hetflag;
              let serial = parseInt(line.substr(6, 5));
              let atom = line.substr(12, 4).replace(/ /g, "");
              let resn = line.substr(17, 3).trim();
              let chain = line.substr(21, 1);
              let resi = parseInt(line.substr(22, 4));
              // however let's split the coordinates, charge and radius by
              // whitespace
              // to support extra precision
              var vals = line.substr(30).trim().split(/\s+/);
              var x = parseFloat(vals[0]);
              var y = parseFloat(vals[1]);
              var z = parseFloat(vals[2]);
              var charge = parseFloat(vals[3]);
              var radius = parseFloat(vals[4]);
 
              var elem = atom[0];
              Iif (atom.length > 1 && atom[1].toUpperCase() != atom[1]) {
                  // slight hack - identify two character elements by the
                  // second character in the atom name being lowercase
                  elem = atom.substr(0, 2);
              }
 
              Iif (line[0] == 'H')
                  hetflag = true;
              else
                  hetflag = false;
              serialToIndex[serial] = atoms[atoms.length-1].length;
              atoms[atoms.length-1].push({
                  'resn' : resn,
                  'x' : x,
                  'y' : y,
                  'z' : z,
                  'elem' : elem,
                  'hetflag' : hetflag,
                  'chain' : chain,
                  'resi' : resi,
                  'serial' : serial,
                  'atom' : atom,
                  'bonds' : [],
                  'ss' : 'c',
                  'bondOrder' : [],
                  'properties' : {
                      'charge' : charge,
                      'partialCharge' : charge,
                      'radius' : radius
                  },
                  'pdbline' : line
              });
          } else Iif (recordName == 'CONECT') {
              // MEMO: We don't have to parse SSBOND, LINK because both are
              // also
              // described in CONECT. But what about 2JYT???
              var from = parseInt(line.substr(6, 5));
              var fromAtom = atoms[atoms.length-1][serialToIndex[from]];
              for (let j = 0; j < 4; j++) {
                  var to = parseInt(line.substr([ 11, 16, 21, 26 ][j], 5));
                  var toAtom = atoms[atoms.length-1][serialToIndex[to]];
                  Iif (fromAtom !== undefined && toAtom !== undefined) {
                      fromAtom.bonds.push(serialToIndex[to]);
                      fromAtom.bondOrder.push(1);
                  }
              }
          }
      }
 
      // assign bonds - yuck, can't count on connect records
      for (let i = 0; i < atoms.length; i++) {
          assignPDBBonds(atoms[i]);
          if (computeStruct)
              computeSecondaryStructure(atoms[i],options.hbondCutoff);
      }
      
      return atoms;
  };