molio.esm.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. /*
  2. * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * from https://github.com/dsehnal/CIFTools.js
  5. * @author David Sehnal <david.sehnal@gmail.com>
  6. */
  7. /**
  8. * Efficient integer and float parsers.
  9. *
  10. * For the purposes of parsing numbers from the mmCIF data representations,
  11. * up to 4 times faster than JS parseInt/parseFloat.
  12. */
  13. function parseInt(str, start, end) {
  14. var ret = 0, neg = 1;
  15. if (str.charCodeAt(start) === 45 /* - */) {
  16. neg = -1;
  17. start++;
  18. }
  19. for (; start < end; start++) {
  20. var c = str.charCodeAt(start) - 48;
  21. if (c > 9 || c < 0)
  22. { return (neg * ret) | 0; }
  23. else
  24. { ret = (10 * ret + c) | 0; }
  25. }
  26. return neg * ret;
  27. }
  28. function parseScientific(main, str, start, end) {
  29. // handle + in '1e+1' separately.
  30. if (str.charCodeAt(start) === 43 /* + */)
  31. { start++; }
  32. return main * Math.pow(10.0, parseInt(str, start, end));
  33. }
  34. function parseFloat(str, start, end) {
  35. var neg = 1.0, ret = 0.0, point = 0.0, div = 1.0;
  36. if (str.charCodeAt(start) === 45) {
  37. neg = -1.0;
  38. ++start;
  39. }
  40. while (start < end) {
  41. var c = str.charCodeAt(start) - 48;
  42. if (c >= 0 && c < 10) {
  43. ret = ret * 10 + c;
  44. ++start;
  45. }
  46. else if (c === -2) {
  47. ++start;
  48. while (start < end) {
  49. c = str.charCodeAt(start) - 48;
  50. if (c >= 0 && c < 10) {
  51. point = 10.0 * point + c;
  52. div = 10.0 * div;
  53. ++start;
  54. }
  55. else if (c === 53 || c === 21) {
  56. return parseScientific(neg * (ret + point / div), str, start + 1, end);
  57. }
  58. else {
  59. return neg * (ret + point / div);
  60. }
  61. }
  62. return neg * (ret + point / div);
  63. }
  64. else if (c === 53 || c === 21) {
  65. return parseScientific(neg * ret, str, start + 1, end);
  66. }
  67. else
  68. { break; }
  69. }
  70. return neg * ret;
  71. }
  72. /**
  73. * Eat everything until a newline occurs.
  74. */
  75. function eatLine(state) {
  76. while (state.position < state.length) {
  77. switch (state.data.charCodeAt(state.position)) {
  78. case 10:// \n
  79. state.currentTokenEnd = state.position;
  80. ++state.position;
  81. ++state.currentLineNumber;
  82. return;
  83. case 13:// \r
  84. state.currentTokenEnd = state.position;
  85. ++state.position;
  86. ++state.currentLineNumber;
  87. if (state.data.charCodeAt(state.position) === 10) {
  88. ++state.position;
  89. }
  90. return;
  91. default:
  92. ++state.position;
  93. }
  94. }
  95. state.currentTokenEnd = state.position;
  96. }
  97. /**
  98. * Eat everything until a whitespace/newline occurs.
  99. */
  100. function eatValue(state) {
  101. while (state.position < state.length) {
  102. switch (state.data.charCodeAt(state.position)) {
  103. case 9: // \t
  104. case 10: // \n
  105. case 13: // \r
  106. case 32:// ' '
  107. state.currentTokenEnd = state.position;
  108. return;
  109. default:
  110. ++state.position;
  111. break;
  112. }
  113. }
  114. state.currentTokenEnd = state.position;
  115. }
  116. /**
  117. * Skips all the whitespace - space, tab, newline, CR
  118. * Handles incrementing line count.
  119. */
  120. function skipWhitespace(state) {
  121. var prev = 10;
  122. while (state.position < state.length) {
  123. var c = state.data.charCodeAt(state.position);
  124. switch (c) {
  125. case 9: // '\t'
  126. case 32:// ' '
  127. prev = c;
  128. ++state.position;
  129. break;
  130. case 10:// \n
  131. // handle \r\n
  132. if (prev !== 13) {
  133. ++state.currentLineNumber;
  134. }
  135. prev = c;
  136. ++state.position;
  137. break;
  138. case 13:// \r
  139. prev = c;
  140. ++state.position;
  141. ++state.currentLineNumber;
  142. break;
  143. default:
  144. return prev;
  145. }
  146. }
  147. return prev;
  148. }
  149. var Tokens;
  150. (function (Tokens) {
  151. function resize(tokens) {
  152. // scale the size using golden ratio, because why not.
  153. var newBuffer = new Int32Array((1.61 * tokens.indices.length) | 0);
  154. newBuffer.set(tokens.indices);
  155. tokens.indices = newBuffer;
  156. tokens.indicesLenMinus2 = (newBuffer.length - 2) | 0;
  157. }
  158. function add(tokens, start, end) {
  159. if (tokens.count > tokens.indicesLenMinus2) {
  160. resize(tokens);
  161. }
  162. tokens.indices[tokens.count++] = start;
  163. tokens.indices[tokens.count++] = end;
  164. }
  165. Tokens.add = add;
  166. function addUnchecked(tokens, start, end) {
  167. tokens.indices[tokens.count++] = start;
  168. tokens.indices[tokens.count++] = end;
  169. }
  170. Tokens.addUnchecked = addUnchecked;
  171. function create(size) {
  172. return {
  173. indicesLenMinus2: (size - 2) | 0,
  174. count: 0,
  175. indices: new Int32Array(size)
  176. };
  177. }
  178. Tokens.create = create;
  179. })(Tokens || (Tokens = {}));
  180. /**
  181. * Represents a column that is not present.
  182. */
  183. var _UndefinedColumn = function _UndefinedColumn() {
  184. this.isDefined = false;
  185. };
  186. _UndefinedColumn.prototype.getString = function getString (row) { return null; };
  187. _UndefinedColumn.prototype.getInteger = function getInteger (row) { return 0; };
  188. _UndefinedColumn.prototype.getFloat = function getFloat (row) { return 0.0; };
  189. _UndefinedColumn.prototype.getValuePresence = function getValuePresence (row) { return 1 /* NotSpecified */; };
  190. _UndefinedColumn.prototype.areValuesEqual = function areValuesEqual (rowA, rowB) { return true; };
  191. _UndefinedColumn.prototype.stringEquals = function stringEquals (row, value) { return value === null; };
  192. var UndefinedColumn = new _UndefinedColumn();
  193. /*
  194. * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
  195. *
  196. * from https://github.com/dsehnal/CIFTools.js
  197. * @author David Sehnal <david.sehnal@gmail.com>
  198. */
  199. var ShortStringPool;
  200. (function (ShortStringPool) {
  201. function create() { return Object.create(null); }
  202. ShortStringPool.create = create;
  203. function get(pool, str) {
  204. if (str.length > 6)
  205. { return str; }
  206. var value = pool[str];
  207. if (value !== void 0)
  208. { return value; }
  209. pool[str] = str;
  210. return str;
  211. }
  212. ShortStringPool.get = get;
  213. })(ShortStringPool || (ShortStringPool = {}));
  214. /**
  215. * Represents a single column.
  216. */
  217. var TextColumn = function TextColumn(table, data, name, index) {
  218. this.data = data;
  219. this.name = name;
  220. this.index = index;
  221. this.stringPool = ShortStringPool.create();
  222. this.isDefined = true;
  223. this.indices = table.indices;
  224. this.columnCount = table.columnCount;
  225. };
  226. /**
  227. * Returns the string value at given row.
  228. */
  229. TextColumn.prototype.getString = function getString (row) {
  230. var i = (row * this.columnCount + this.index) * 2;
  231. return ShortStringPool.get(this.stringPool, this.data.substring(this.indices[i], this.indices[i + 1]));
  232. };
  233. /**
  234. * Returns the integer value at given row.
  235. */
  236. TextColumn.prototype.getInteger = function getInteger (row) {
  237. var i = (row * this.columnCount + this.index) * 2;
  238. return parseInt(this.data, this.indices[i], this.indices[i + 1]);
  239. };
  240. /**
  241. * Returns the float value at given row.
  242. */
  243. TextColumn.prototype.getFloat = function getFloat (row) {
  244. var i = (row * this.columnCount + this.index) * 2;
  245. return parseFloat(this.data, this.indices[i], this.indices[i + 1]);
  246. };
  247. /**
  248. * Returns true if the token has the specified string value.
  249. */
  250. TextColumn.prototype.stringEquals = function stringEquals (row, value) {
  251. var this$1 = this;
  252. var aIndex = (row * this.columnCount + this.index) * 2, s = this.indices[aIndex], len = value.length;
  253. if (len !== this.indices[aIndex + 1] - s)
  254. { return false; }
  255. for (var i = 0; i < len; i++) {
  256. if (this$1.data.charCodeAt(i + s) !== value.charCodeAt(i))
  257. { return false; }
  258. }
  259. return true;
  260. };
  261. /**
  262. * Determines if values at the given rows are equal.
  263. */
  264. TextColumn.prototype.areValuesEqual = function areValuesEqual (rowA, rowB) {
  265. var this$1 = this;
  266. var aIndex = (rowA * this.columnCount + this.index) * 2;
  267. var bIndex = (rowB * this.columnCount + this.index) * 2;
  268. var aS = this.indices[aIndex];
  269. var bS = this.indices[bIndex];
  270. var len = this.indices[aIndex + 1] - aS;
  271. if (len !== this.indices[bIndex + 1] - bS)
  272. { return false; }
  273. for (var i = 0; i < len; i++) {
  274. if (this$1.data.charCodeAt(i + aS) !== this$1.data.charCodeAt(i + bS)) {
  275. return false;
  276. }
  277. }
  278. return true;
  279. };
  280. TextColumn.prototype.getValuePresence = function getValuePresence (row) {
  281. var index = 2 * (row * this.columnCount + this.index);
  282. if (this.indices[index] === this.indices[index + 1]) {
  283. return 1 /* NotSpecified */;
  284. }
  285. return 0 /* Present */;
  286. };
  287. var CifColumn = (function (TextColumn) {
  288. function CifColumn () {
  289. TextColumn.apply(this, arguments);
  290. }
  291. if ( TextColumn ) CifColumn.__proto__ = TextColumn;
  292. CifColumn.prototype = Object.create( TextColumn && TextColumn.prototype );
  293. CifColumn.prototype.constructor = CifColumn;
  294. CifColumn.prototype.getString = function getString (row) {
  295. var ret = TextColumn.prototype.getString.call(this, row);
  296. if (ret === '.' || ret === '?')
  297. { return null; }
  298. return ret;
  299. };
  300. /**
  301. * Returns true if the value is not defined (. or ? token).
  302. */
  303. CifColumn.prototype.getValuePresence = function getValuePresence (row) {
  304. var index = 2 * (row * this.columnCount + this.index);
  305. var s = this.indices[index];
  306. if (this.indices[index + 1] - s !== 1)
  307. { return 0 /* Present */; }
  308. var v = this.data.charCodeAt(s);
  309. if (v === 46 /* . */)
  310. { return 1 /* NotSpecified */; }
  311. if (v === 63 /* ? */)
  312. { return 2 /* Unknown */; }
  313. return 0 /* Present */;
  314. };
  315. return CifColumn;
  316. }(TextColumn));
  317. /**
  318. * Represents a table backed by a string.
  319. */
  320. var TextTable = function TextTable(data, name, columns, tokens) {
  321. this.name = name;
  322. this.indices = tokens.indices;
  323. this.data = data;
  324. this.columnCount = columns.length;
  325. this.rowCount = (tokens.count / 2 / columns.length) | 0;
  326. this.initColumns(columns);
  327. };
  328. var prototypeAccessors = { columnNames: {} };
  329. prototypeAccessors.columnNames.get = function () {
  330. return this.columnNameList;
  331. };
  332. /**
  333. * Get a column object that makes accessing data easier.
  334. */
  335. TextTable.prototype.getColumn = function getColumn (name) {
  336. var i = this.columnIndices.get(name);
  337. if (i !== void 0)
  338. { return new TextColumn(this, this.data, name, i); }
  339. return UndefinedColumn;
  340. };
  341. TextTable.prototype.initColumns = function initColumns (columns) {
  342. var this$1 = this;
  343. this.columnIndices = new Map();
  344. this.columnNameList = [];
  345. for (var i = 0; i < columns.length; i++) {
  346. this$1.columnIndices.set(columns[i], i);
  347. this$1.columnNameList.push(columns[i]);
  348. }
  349. };
  350. Object.defineProperties( TextTable.prototype, prototypeAccessors );
  351. var CifTable = (function (TextTable) {
  352. function CifTable () {
  353. TextTable.apply(this, arguments);
  354. }
  355. if ( TextTable ) CifTable.__proto__ = TextTable;
  356. CifTable.prototype = Object.create( TextTable && TextTable.prototype );
  357. CifTable.prototype.constructor = CifTable;
  358. CifTable.prototype.getColumn = function getColumn (name) {
  359. var i = this.columnIndices.get(name);
  360. if (i !== void 0)
  361. { return new CifColumn(this, this.data, name, i); }
  362. return UndefinedColumn;
  363. };
  364. CifTable.prototype.initColumns = function initColumns (columns) {
  365. var this$1 = this;
  366. this.columnIndices = new Map();
  367. this.columnNameList = [];
  368. for (var i = 0; i < columns.length; i++) {
  369. var colName = columns[i].substr(this$1.name.length + 1);
  370. this$1.columnIndices.set(colName, i);
  371. this$1.columnNameList.push(colName);
  372. }
  373. };
  374. return CifTable;
  375. }(TextTable));
  376. /*
  377. * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
  378. *
  379. * from https://github.com/dsehnal/CIFTools.js
  380. * @author David Sehnal <david.sehnal@gmail.com>
  381. */
  382. var ParserResult;
  383. (function (ParserResult) {
  384. function error(message, line) {
  385. if ( line === void 0 ) line = -1;
  386. return new ParserError(message, line);
  387. }
  388. ParserResult.error = error;
  389. function success(result, warnings) {
  390. if ( warnings === void 0 ) warnings = [];
  391. return new ParserSuccess(result, warnings);
  392. }
  393. ParserResult.success = success;
  394. })(ParserResult || (ParserResult = {}));
  395. var ParserError = function ParserError(message, line) {
  396. this.message = message;
  397. this.line = line;
  398. this.isError = true;
  399. };
  400. ParserError.prototype.toString = function toString () {
  401. if (this.line >= 0) {
  402. return ("[Line " + (this.line) + "] " + (this.message));
  403. }
  404. return this.message;
  405. };
  406. var ParserSuccess = function ParserSuccess(result, warnings) {
  407. this.result = result;
  408. this.warnings = warnings;
  409. this.isError = false;
  410. };
  411. /*
  412. * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
  413. *
  414. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  415. */
  416. var GroFile = function GroFile(data) {
  417. this.blocks = [];
  418. this.data = data;
  419. };
  420. var GroBlock = function GroBlock(data) {
  421. this.data = data;
  422. this.tableMap = new Map();
  423. this.tableList = [];
  424. };
  425. GroBlock.prototype.getTable = function getTable (name) {
  426. return this.tableMap.get(name);
  427. };
  428. /**
  429. * Adds a table.
  430. */
  431. GroBlock.prototype.addTable = function addTable (table) {
  432. this.tableList[this.tableList.length] = table;
  433. this.tableMap.set(table.name, table);
  434. };
  435. function createTokenizer(data) {
  436. return {
  437. data: data,
  438. position: 0,
  439. length: data.length,
  440. currentLineNumber: 1,
  441. currentTokenStart: 0,
  442. currentTokenEnd: 0,
  443. numberOfAtoms: 0,
  444. hasVelocities: false,
  445. numberOfDecimalPlaces: 3
  446. };
  447. }
  448. /**
  449. * title string (free format string, optional time in ps after 't=')
  450. */
  451. function handleTitleString(state, tokens) {
  452. eatLine(state);
  453. // console.log('title', state.data.substring(state.currentTokenStart, state.currentTokenEnd))
  454. var start = state.currentTokenStart;
  455. var end = state.currentTokenEnd;
  456. var valueStart = state.currentTokenStart;
  457. var valueEnd = start;
  458. while (valueEnd < end && !isTime(state.data, valueEnd))
  459. { ++valueEnd; }
  460. if (isTime(state.data, valueEnd)) {
  461. var timeStart = valueEnd + 2;
  462. while (valueEnd > start && isSpaceOrComma(state.data, valueEnd - 1))
  463. { --valueEnd; }
  464. Tokens.add(tokens, valueStart, valueEnd); // title
  465. while (timeStart < end && state.data.charCodeAt(timeStart) === 32)
  466. { ++timeStart; }
  467. while (valueEnd > timeStart && state.data.charCodeAt(valueEnd - 1) === 32)
  468. { --valueEnd; }
  469. Tokens.add(tokens, timeStart, end); // time
  470. }
  471. else {
  472. Tokens.add(tokens, valueStart, valueEnd); // title
  473. Tokens.add(tokens, valueEnd, valueEnd); // empty token for time
  474. }
  475. }
  476. function isSpaceOrComma(data, position) {
  477. var c = data.charCodeAt(position);
  478. return c === 32 || c === 44;
  479. }
  480. function isTime(data, position) {
  481. // T/t
  482. var c = data.charCodeAt(position);
  483. if (c !== 84 && c !== 116)
  484. { return false; }
  485. // =
  486. if (data.charCodeAt(position + 1) !== 61)
  487. { return false; }
  488. return true;
  489. }
  490. // function isDot(state: TokenizerState): boolean {
  491. // // .
  492. // if (state.data.charCodeAt(state.currentTokenStart) !== 46) return false;
  493. // return true;
  494. // }
  495. // function numberOfDecimalPlaces (state: TokenizerState) {
  496. // // var ndec = firstLines[ 2 ].length - firstLines[ 2 ].lastIndexOf('.') - 1
  497. // const start = state.currentTokenStart
  498. // const end = state.currentTokenEnd
  499. // for (let i = end; start < i; --i) {
  500. // // .
  501. // if (state.data.charCodeAt(i) === 46) return end - start - i
  502. // }
  503. // throw new Error('Could not determine number of decimal places')
  504. // }
  505. /**
  506. * number of atoms (free format integer)
  507. */
  508. function handleNumberOfAtoms(state, tokens) {
  509. skipWhitespace(state);
  510. state.currentTokenStart = state.position;
  511. eatValue(state);
  512. state.numberOfAtoms = parseInt(state.data, state.currentTokenStart, state.currentTokenEnd);
  513. Tokens.add(tokens, state.currentTokenStart, state.currentTokenEnd);
  514. eatLine(state);
  515. }
  516. // function checkForVelocities (state: GroState) {
  517. // }
  518. /**
  519. * This format is fixed, ie. all columns are in a fixed position.
  520. * Optionally (for now only yet with trjconv) you can write gro files
  521. * with any number of decimal places, the format will then be n+5
  522. * positions with n decimal places (n+1 for velocities) in stead
  523. * of 8 with 3 (with 4 for velocities). Upon reading, the precision
  524. * will be inferred from the distance between the decimal points
  525. * (which will be n+5). Columns contain the following information
  526. * (from left to right):
  527. * residue number (5 positions, integer)
  528. * residue name (5 characters)
  529. * atom name (5 characters)
  530. * atom number (5 positions, integer)
  531. * position (in nm, x y z in 3 columns, each 8 positions with 3 decimal places)
  532. * velocity (in nm/ps (or km/s), x y z in 3 columns, each 8 positions with 4 decimal places)
  533. */
  534. function handleAtoms(state, block) {
  535. var name = 'atoms';
  536. var columns = ['residueNumber', 'residueName', 'atomName', 'atomNumber', 'x', 'y', 'z'];
  537. if (state.hasVelocities) {
  538. columns.push('vx', 'vy', 'vz');
  539. }
  540. var fieldSizes = [5, 5, 5, 5, 8, 8, 8, 8, 8, 8];
  541. var columnCount = columns.length;
  542. var tokens = Tokens.create(state.numberOfAtoms * 2 * columnCount);
  543. var start;
  544. var end;
  545. var valueStart;
  546. var valueEnd = state.position;
  547. for (var i = 0; i < state.numberOfAtoms; ++i) {
  548. state.currentTokenStart = state.position;
  549. end = state.currentTokenStart;
  550. for (var j = 0; j < columnCount; ++j) {
  551. start = end;
  552. end = start + fieldSizes[j];
  553. // trim
  554. valueStart = start;
  555. valueEnd = end;
  556. while (valueStart < valueEnd && state.data.charCodeAt(valueStart) === 32)
  557. { ++valueStart; }
  558. while (valueEnd > valueStart && state.data.charCodeAt(valueEnd - 1) === 32)
  559. { --valueEnd; }
  560. Tokens.addUnchecked(tokens, valueStart, valueEnd);
  561. }
  562. state.position = valueEnd;
  563. eatLine(state);
  564. }
  565. block.addTable(new TextTable(state.data, name, columns, tokens));
  566. }
  567. /**
  568. * box vectors (free format, space separated reals), values:
  569. * v1(x) v2(y) v3(z) v1(y) v1(z) v2(x) v2(z) v3(x) v3(y),
  570. * the last 6 values may be omitted (they will be set to zero).
  571. * Gromacs only supports boxes with v1(y)=v1(z)=v2(z)=0.
  572. */
  573. function handleBoxVectors(state, tokens) {
  574. // just read the first three values, ignore any remaining
  575. for (var i = 0; i < 3; ++i) {
  576. skipWhitespace(state);
  577. state.currentTokenStart = state.position;
  578. eatValue(state);
  579. Tokens.add(tokens, state.currentTokenStart, state.currentTokenEnd);
  580. }
  581. }
  582. /**
  583. * Creates an error result.
  584. */
  585. // function error(line: number, message: string) {
  586. // return ParserResult.error<GroFile>(message, line);
  587. // }
  588. /**
  589. * Creates a data result.
  590. */
  591. function result(data) {
  592. return ParserResult.success(data);
  593. }
  594. function parseInternal(data) {
  595. var state = createTokenizer(data);
  596. var file = new GroFile(data);
  597. var block = new GroBlock(data);
  598. file.blocks.push(block);
  599. var headerColumns = ['title', 'timeInPs', 'numberOfAtoms', 'boxX', 'boxY', 'boxZ'];
  600. var headerTokens = Tokens.create(2 * headerColumns.length);
  601. var header = new TextTable(state.data, 'header', headerColumns, headerTokens);
  602. block.addTable(header);
  603. handleTitleString(state, headerTokens);
  604. handleNumberOfAtoms(state, headerTokens);
  605. handleAtoms(state, block);
  606. handleBoxVectors(state, headerTokens);
  607. return result(file);
  608. }
  609. function parse(data) {
  610. return parseInternal(data);
  611. }
  612. export { parse as groReader };
  613. //# sourceMappingURL=molio.esm.js.map