Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/alkihis/itp-parser
A simple ITP/TOP parser in JavaScript
https://github.com/alkihis/itp-parser
Last synced: about 1 month ago
JSON representation
A simple ITP/TOP parser in JavaScript
- Host: GitHub
- URL: https://github.com/alkihis/itp-parser
- Owner: alkihis
- Created: 2020-04-29T13:58:46.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2021-11-18T15:18:48.000Z (about 3 years ago)
- Last Synced: 2024-10-06T18:47:36.397Z (about 1 month ago)
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/itp-parser
- Size: 60.5 KB
- Stars: 0
- Watchers: 2
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# itp-parser
> A basic ITP/TOP file parser
## Getting started
Install the package using npm.
```bash
npm i itp-parser
```This package exports two objects: `ItpFile` and `TopFile`, whose have obvious usages.
Default export is `ItpFile`.```ts
// ECMA Modules
import ItpFile, { TopFile } from 'itp-parser';
// or
import { ItpFile, TopFile } from 'itp-parser';// CommonJS modules
const { ItpFile, TopFile } = require('itp-parser');
```## Use target of `ItpFile` and `TopFile` instances
### `ItpFile` instance
- Hold a single molecule definition
- None or one `moleculetype` field per instance### `TopFile` instance
- From a `molecules` field, associate every described molecule to a `ItpFile` instance
- System name## Usage
### A word about the parser
This parser handle only basic parsing:
It does **not** resolve includes, and it does **not** consider *`#define`*, *`#ifdef`* or other preprocessor statements.Lines that contains those preprocessors are stored as plain lines in field definitions.
To have a support of includes and basic support of preprocessors, see `AdvancedTopFile` object.
### About accepted types for ITP instanciation
Async instanciation accepts `string` (as file path), `NodeJS.ReadableStream` and `File`/`Blob` objects (from browser).
Sync instanciation accepts `string` (as file content).
### Read an ITP with none/single moleculetype field
The following sections will talk about the `ItpFile` object.
---
If you know that your ITP file does not contain a molecule (`moleculetype`) definition,
or contains only one definition,
use `ItpFile.read()` or `ItpFile.readFromString()` as constructor.```ts
import { ItpFile } from 'itp-parser';
import fs from 'fs';// Read asynchrounously
(async () => {
// Single line instanciation
// With file path
const file = await ItpFile.read('/path/to/file');
// With a readable stream
const file = await ItpFile.read(fs.createReadStream('/path/to/file'));
// With a File/Blob (inside a browser)
const file = await ItpFile.read(document.querySelector('input[type="file"]').files[0]);console.log("This ITP hold moleculetype", file.name);
// {file} is ready !
})();// Read synchronously
const file = ItpFile.readFromString(fs.readFileSync('/path/to/file.itp', 'utf-8'));
// {file} is ready
```### Read an ITP with none/single/multiple moleculetype field
If your ITP contain multiple molecule definitions, or if you don't know how many `moleculetype` are presents
in the targeted ITP, use `ItpFile.readMany()` or `ItpFile.readManyFromString()` as constructor.It both returns a array of `ItpFile`, once per `moleculetype` definition.
If the ITP does not contain any `moleculetype`, an array of one `ItpFile` is returned.
```ts
import { ItpFile } from 'itp-parser';// Asynchrounously
(async () => {
const itps = await ItpFile.readMany('/path/to/file');for (const itp of itps) {
console.log("ITP: moleculetype", itp.name);
}// All itps are ready !
})();// Read synchronously
const itps = ItpFile.readManyFromString(fs.readFileSync('/path/to/file.itp', 'utf-8'));
```### Access a field
Every field is an array of strings (array of lines).
```ts
file.getField('{field_name}'); // => string[] (every line contained in the field. Empty lines are skipped.)// For example: Access to all atoms
file.getField('atoms');// Get a field without the lines that are only comments
file.getField('atoms', true);
```#### Shortcuts
Some fields have direct accessor:
```ts
file.name; // Name/Type. Read from moleculetype
file.name_and_nrexcl; // => [string, number]. parsed version of file.getField('moleculetype')
file.atoms; // string[]. Equivalent to file.getField('atoms')
file.bonds; // string[]. Equivalent to file.getField('bonds')
file.virtual_sites; // string[]. Equivalent to file.getField('virtual_sitesn')
```#### Access to data before every field
Lines read before encountering a single field declaration are stored in `.headlines`.
```ts
file.headlines; // => string[]
```### Write ITPs
You can change data of a field with `.setField(name, lines)` and create a read stream of this ITP with `.asReadStream()`.
```ts
import fs from 'fs';// Change the atom field with modified data
file.setField('atoms', file.atoms.filter(line => line.split(/\s+/).length > 3));// Write the new ITP
const writestm = fs.createWriteStream('/path/to/output.itp');new Promise((resolve, reject) => {
const reads = file.asReadStream();reads.on('close', resolve);
reads.on('error', reject);
writestm.on('error', reject);
reads.pipe(writestm);
}).then(() => {
console.log("Write is over !");
}).catch(e => {
console.log("An error occured.", e);
});
```A `.toString()` method is also available to return the formatted ITP as a plain string.
```ts
const file_as_string = file.toString(); // or String(file)fs.writeFileSync('/path/to/output.itp', file_as_string);
```### Read a full system with a TOP file and ITPs
The following sections will talk about the `TopFile` object.
---
With the `TopFile` object, you can read a TOP file and associated ITPs.
In order to link `moleculetype` described in `molecules` field of TOP with ITP data, you either:
- Have to manually resolve the included files before reading the TOP file, and specify ITP files in constructor
- Sideload manually the ITPs```ts
// Asynchronously
const top = await TopFile.read('/path/to/top', ['/path/to/itp1', '/path/to/itp2']);// Synchronously
const top = TopFile.readFromString(
fs.readFileSync('/path/to/top', 'utf-8'),
[
fs.readFileSync('/path/to/itp1', 'utf-8'),
fs.readFileSync('/path/to/itp2', 'utf-8'),
]
);// {top} is ready !
```### List molecules of a system
```ts
for (const molecule of top.molecules) {
console.log("Molecule", molecule.type, ":", molecule.count, "times in the system");
}
```### Sideload ITPs in a system
When you know which `moleculetype` is present in the system, you can load inside the `TopFile` instance the ITPs you want.
```ts
// Asynchronously
await top.sideloadItp('/path/to/itp');// Synchronously
top.sideloadItpFromString(fs.readFileSync('/path/to/itp', 'utf-8'));
```For example, if your system contain `DPPC`:
```ts
// If your file contains multiple moleculetype, they're all parsed in async mode
await top.sideloadItp('lipids.itp');top.molecules.filter(e => e.type === "DPPC")[0].itp; // => ItpFile
```### Get a molecule by name in a system
A molecule can be described multiple times in a system, for example:
```itp
[ molecules ]
molecule_0 2
molecule_1 3
molecule_0 1
```
is a valid format for GROMACS.
For this reason, a molecule type can be present multiple time in the `top.molecules` array.`top.molecules` is an array of `MoleculeDefinition`.
```ts
interface MoleculeDefinition {
itp: ItpFile,
count: number,
type: string
}
```The first `string` is the molecule type,
and the `MoleculeDefinition` is an object containing two fields:
- `itp`: Contains the related `ItpFile` for this molecule type
- `count`: Associated count of the molecule type, number on the right in exampleIn order to access `ItpFile` instance, you must provide the ITP for the given `moleculetype` in the constructor.
```ts
const molecules = top.molecules.filter(e => e.type === "DPPC");if (molecules) {
console.log("Molecule DPPC is present", molecules.reduce((acc, cur) => acc + cur.count, 0), "times in the system");
}
```The `TopFile` instance inherits from `ItpFile`, so all methods presented before are accessible with.
### Advanced TOP parser
`AdvancedTopFile` have a similar API of `TopFile`, except some points.
Therefore, unlike the other classes, you must instanciate it with the constructor then using `.read(what: ReadEntry, onInclude: Includer)`.
This class accepts files with a `ReadEntry` partial object.
```ts
interface ReadEntry {
path: string;
stream: NodeJS.ReadableStream;
content: string;
file: Blob;
/** Only valid on return of a `on_include` closure. */
none: true;
}
```
To specify which file you want to load, fill **only one** of the properties of the object.In order to resolve includes, you must specify a callback (async or not) that returns a `ReadEntry` as the second parameter of `.read` method.
```ts
type Includer = (filename: string) => Partial | Promise>;
```---
Let's see how it works with an example:
```ts
import { AdvancedTopFile } from 'itp-parser';
import fs, { promises as FsPromise } from 'fs';const top = new AdvancedTopFile(/* enable_preprocessors = */ true);
await top.read(
/* the file to read */ { path: '/path/to/file.top' },
/* when a file is included */
async (name: string) => {
const exists = await FsPromise.access(name, fs.F_OK)
.then(() => true)
.catch(() => false);if (exists) {
// If file exists, include it as path
return { path: name };
}
// Otherwise, fill the none field (do not include it)
return { none: true };
}
);// Your whole system described by file.top is ready,
// even included files are resolved !
```The following methods/properties are available:
- `.define(name: string)`: To do before `.read()`; Define a macro, like `#define NAME` in a ITP file
- All the methods of `ItpFile`, this object inherits from it
- The same as `TopFile`:
- `.registred_itps`: A `Set` of all molecules as `ItpFile`s
- `.molecules`: A `MoleculeDefinition` array
- `.name`: Name of the system
- `.getMolecule(name: string)`: A `MoleculeDefinition` array containing all occurence of molecule `{name}`
- `.includes`: All the `#include` lines (they're not inside the fields arrays, so you can find them here)
- `.toString()` and `.asReadStream()`: a `string`/`stream.Readable` representation of the system; all included files are emitted in the stream, so the system could be written a a single file## Self-installation
This module is written in TypeScript.
In order to use it, you must have the TypeScript compiler installed.```bash
git clone https://github.com/alkihis/itp-parser.git
cd itp-parser
npm i
tsc
# Compiled JS entrypoint is in dist/index.js
```