From 135635ac0673835fda9ea7eda009e327752aee71 Mon Sep 17 00:00:00 2001
From: David Sehnal <david.sehnal@gmail.com>
Date: Sat, 23 Sep 2017 14:47:54 +0200
Subject: [PATCH] Changed data model, updated GRO parser to handle velocities,
 arbitrary precision, multiple models

---
 README.md                                     |   6 +-
 package-lock.json                             | Bin 0 -> 131693 bytes
 package.json                                  |   9 +-
 src/{data => reader/cif}/data.ts              |   3 -
 src/{data => reader/cif}/schema.ts            |   3 -
 src/reader/common/column.ts                   |  43 ++++
 src/reader/common/spec/fixed-column.spec.ts   |  50 +++++
 src/reader/common/text/column/__token.ts      | 114 ++++++++++
 src/reader/common/text/column/fixed.ts        |  53 +++++
 src/reader/common/text/token-field.ts         | 114 ----------
 src/reader/common/text/tokenizer.ts           |  61 ++++--
 src/reader/gro/format.ts                      |  14 --
 src/reader/gro/parser.ts                      | 206 +++++++++---------
 src/reader/gro/schema.d.ts                    |  40 ++++
 src/reader/gro/schema.ts                      |  40 ----
 .../spec/cif.spec.ts}                         |   5 +-
 src/reader/spec/gro.spec.ts                   | 115 +++++-----
 src/script.ts                                 |  84 ++++---
 18 files changed, 550 insertions(+), 410 deletions(-)
 create mode 100644 package-lock.json
 rename src/{data => reader/cif}/data.ts (95%)
 rename src/{data => reader/cif}/schema.ts (96%)
 create mode 100644 src/reader/common/column.ts
 create mode 100644 src/reader/common/spec/fixed-column.spec.ts
 create mode 100644 src/reader/common/text/column/__token.ts
 create mode 100644 src/reader/common/text/column/fixed.ts
 delete mode 100644 src/reader/common/text/token-field.ts
 delete mode 100644 src/reader/gro/format.ts
 create mode 100644 src/reader/gro/schema.d.ts
 delete mode 100644 src/reader/gro/schema.ts
 rename src/{data/spec/schema.spec.ts => reader/spec/cif.spec.ts} (95%)

diff --git a/README.md b/README.md
index 5b2a0416a..30294cdc0 100644
--- a/README.md
+++ b/README.md
@@ -43,8 +43,4 @@
 TODO
 ----
 
-- write about unittest (AR)
-- gro reader
-  - read more than one block
-  - read velocities
-  - detect number of decimal places
+- write about unittest (AR)
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..e211546c2e17aecf72e79eabc20961af48563ceb
GIT binary patch
literal 131693
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

literal 0
HcmV?d00001

diff --git a/package.json b/package.json
index c1de25f15..ddb398263 100644
--- a/package.json
+++ b/package.json
@@ -15,8 +15,13 @@
     "script": "./node_modules/.bin/rollup build/js/src/script.js -e fs -f cjs -o build/js/script.js"
   },
   "jest": {
-    "moduleFileExtensions": [ "ts", "js" ],
-    "transform": { "\\.ts$": "<rootDir>/node_modules/ts-jest/preprocessor.js" },
+    "moduleFileExtensions": [
+      "ts",
+      "js"
+    ],
+    "transform": {
+      "\\.ts$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
+    },
     "testRegex": "\\.spec\\.ts$"
   },
   "author": "",
diff --git a/src/data/data.ts b/src/reader/cif/data.ts
similarity index 95%
rename from src/data/data.ts
rename to src/reader/cif/data.ts
index 849a0954e..6d85c6a83 100644
--- a/src/data/data.ts
+++ b/src/reader/cif/data.ts
@@ -56,9 +56,6 @@ export interface Field {
     int(row: number): number,
     float(row: number): number,
 
-    /** The 'intrinsic value' of the field, e.g., array, binary data, ... */
-    value(row: number): any,
-
     presence(row: number): ValuePresence,
 
     areValuesEqual(rowA: number, rowB: number): boolean,
diff --git a/src/data/schema.ts b/src/reader/cif/schema.ts
similarity index 96%
rename from src/data/schema.ts
rename to src/reader/cif/schema.ts
index c9f1a1a86..9db6cb797 100644
--- a/src/data/schema.ts
+++ b/src/reader/cif/schema.ts
@@ -67,7 +67,6 @@ export namespace Field {
     export function str(spec?: Spec) { return createSchema(spec, Str); }
     export function int(spec?: Spec) { return createSchema(spec, Int); }
     export function float(spec?: Spec) { return createSchema(spec, Float); }
-    export function value<T>(spec?: Spec): Schema<T> { return createSchema(spec, Value); }
 
     function create<T>(field: Data.Field, value: (row: number) => T, toArray: Field<T>['toArray']): Field<T> {
         return { isDefined: field.isDefined, value, presence: field.presence, areValuesEqual: field.areValuesEqual, stringEquals: field.stringEquals, toArray };
@@ -76,14 +75,12 @@ export namespace Field {
     function Str(field: Data.Field) { return create(field, field.str, field.toStringArray); }
     function Int(field: Data.Field) { return create(field, field.int, field.toIntArray); }
     function Float(field: Data.Field) { return create(field, field.float, field.toFloatArray); }
-    function Value(field: Data.Field) { return create(field, field.value, () => { throw Error('not supported'); }); }
 
     const DefaultUndefined: Data.Field = {
         isDefined: false,
         str: row => null,
         int: row => 0,
         float: row => 0,
-        value: row => null,
 
         presence: row => Data.ValuePresence.NotSpecified,
         areValuesEqual: (rowA, rowB) => true,
diff --git a/src/reader/common/column.ts b/src/reader/common/column.ts
new file mode 100644
index 000000000..6a2cd768b
--- /dev/null
+++ b/src/reader/common/column.ts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+export type ArrayType = string[] | number[] | Float32Array | Float64Array | Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array
+export type ColumnType = typeof ColumnType.str | typeof ColumnType.int | typeof ColumnType.float
+
+export namespace ColumnType {
+    export const str = { '@type': '' as string, kind: 'str' as 'str' };
+    export const int = { '@type': 0 as number, kind: 'int' as 'int' };
+    export const float = { '@type': 0 as number, kind: 'float' as 'float' };
+}
+
+export interface Column<T> {
+    readonly isColumnDefined: boolean,
+    readonly rowCount: number,
+    value(row: number): T,
+    toArray(ctor?: (size: number) => ArrayType, startRow?: number, endRowExclusive?: number): ReadonlyArray<T>
+}
+
+export function UndefinedColumn<T extends ColumnType>(rowCount: number, type: T): Column<T['@type']> {
+    const value: Column<T['@type']>['value'] = type.kind === 'str' ? row => '' : row => 0;
+    return {
+        isColumnDefined: false,
+        rowCount,
+        value,
+        toArray(ctor, s, e) {
+            const { array } = createArray(rowCount, ctor, s, e);
+            for (let i = 0, _i = array.length; i < _i; i++) array[i] = value(0)
+            return array;
+        }
+    }
+}
+
+/** A helped function for Column.toArray */
+export function createArray(rowCount: number, ctor?: (size: number) => ArrayType, start?: number, end?: number) {
+    const c = typeof ctor !== 'undefined' ? ctor : (s: number) => new Array(s);
+    const s = typeof start !== 'undefined' ? Math.max(Math.min(start, rowCount - 1), 0) : 0;
+    const e = typeof end !== 'undefined' ? Math.min(end, rowCount) : rowCount;
+    return { array: c(e - s) as any[], start: s, end: e };
+}
\ No newline at end of file
diff --git a/src/reader/common/spec/fixed-column.spec.ts b/src/reader/common/spec/fixed-column.spec.ts
new file mode 100644
index 000000000..4aa5e3f24
--- /dev/null
+++ b/src/reader/common/spec/fixed-column.spec.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import FixedColumn from '../text/column/fixed'
+import { ColumnType } from '../../common/column'
+
+const lines = [
+    '1.123 abc',
+    '1.00  a',
+    '1.1    bcd   ',
+    '',
+    ' 5'
+]
+
+const data = lines.join('\n');
+
+const linesTokens = (function () {
+    const tokens: number[] = [];
+    let last = 0;
+    for (const l of lines) {
+        tokens.push(last, last + l.length);
+        last += l.length + 1;
+    }
+    if (tokens[tokens.length - 1] > data.length) tokens[tokens.length - 1] = data.length;
+    return tokens;
+}());
+
+describe('fixed text column', () => {
+    const col = FixedColumn({ data, lines: linesTokens, rowCount: lines.length });
+    const col1 = col(0, 5, ColumnType.float);
+    const col2 = col(5, 4, ColumnType.str);
+    it('number', () => {
+        expect(col1.value(0)).toBe(1.123);
+        expect(col1.value(1)).toBe(1.0);
+        expect(col1.value(2)).toBe(1.1);
+        expect(col1.value(3)).toBe(0);
+        expect(col1.value(4)).toBe(5);
+    })
+    it('str', () => {
+        expect(col2.value(0)).toBe('abc');
+        expect(col2.value(1)).toBe('a');
+        expect(col2.value(2)).toBe('bc');
+        expect(col2.value(3)).toBe('');
+        expect(col2.value(4)).toBe('');
+    })
+});
diff --git a/src/reader/common/text/column/__token.ts b/src/reader/common/text/column/__token.ts
new file mode 100644
index 000000000..87326c26d
--- /dev/null
+++ b/src/reader/common/text/column/__token.ts
@@ -0,0 +1,114 @@
+// /*
+//  * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+//  *
+//  * @author David Sehnal <david.sehnal@gmail.com>
+//  */
+
+// import * as Data from '../../../../data/data'
+// import { parseInt as fastParseInt, parseFloat as fastParseFloat } from '../number-parser'
+// import { Tokens } from '../tokenizer'
+// import ShortStringPool from '../../../../utils/short-string-pool'
+
+// export function createTokenFields(data: string, fields: string[], tokens: Tokens): { [name: string]: Data.Field } {
+//     const fi: TokenFieldInfo = { data, fieldCount: fields.length, tokens: tokens.indices };
+//     const categoryFields = Object.create(null);
+//     for (let i = 0; i < fi.fieldCount; ++i) {
+//         categoryFields[fields[i]] = TokenField(fi, i);
+//     }
+//     return categoryFields;
+// }
+
+// export interface TokenFieldInfo {
+//     data: string,
+//     tokens: ArrayLike<number>,
+//     fieldCount: number,
+//     isCif?: boolean
+// }
+
+// export function TokenField(info: TokenFieldInfo, index: number): Data.Field {
+//     const { data, tokens, fieldCount, isCif = false } = info;
+//     const stringPool = ShortStringPool.create();
+
+//     const str: Data.Field['str'] = isCif ? row => {
+//         const i = (row * fieldCount + index) * 2;
+//         const ret = ShortStringPool.get(stringPool, data.substring(tokens[i], tokens[i + 1]));
+//         if (ret === '.' || ret === '?') return null;
+//         return ret;
+//     } : row => {
+//         const i = (row * fieldCount + index) * 2;
+//         return ShortStringPool.get(stringPool, data.substring(tokens[i], tokens[i + 1]));
+//     };
+
+//     const int: Data.Field['int'] = row => {
+//         const i = (row * fieldCount + index) * 2;
+//         return fastParseInt(data, tokens[i], tokens[i + 1]) || 0;
+//     };
+
+//     const float: Data.Field['float'] = row => {
+//         const i = (row * fieldCount + index) * 2;
+//         return fastParseFloat(data, tokens[i], tokens[i + 1]) || 0;
+//     };
+
+//     const presence: Data.Field['presence'] = isCif ? row => {
+//         const i = 2 * (row * fieldCount + index);
+//         const s = tokens[i];
+//         if (tokens[i + 1] - s !== 1) return Data.ValuePresence.Present;
+//         const v = data.charCodeAt(s);
+//         if (v === 46 /* . */) return Data.ValuePresence.NotSpecified;
+//         if (v === 63 /* ? */) return Data.ValuePresence.Unknown;
+//         return Data.ValuePresence.Present;
+//     } : row => {
+//         const i = 2 * (row * fieldCount + index);
+//         return tokens[i] === tokens[i + 1] ? Data.ValuePresence.NotSpecified : Data.ValuePresence.Present
+//     };
+
+//     return {
+//         isDefined: true,
+//         str,
+//         int,
+//         float,
+//         value: str,
+//         presence,
+//         areValuesEqual: (rowA, rowB) => {
+//             const aI = (rowA * fieldCount + index) * 2, aS = tokens[aI];
+//             const bI = (rowB * fieldCount + index) * 2, bS = tokens[bI];
+//             const len = tokens[aI + 1] - aS;
+//             if (len !== tokens[bI + 1] - bS) return false;
+//             for (let i = 0; i < len; i++) {
+//                 if (data.charCodeAt(i + aS) !== data.charCodeAt(i + bS)) {
+//                     return false;
+//                 }
+//             }
+//             return true;
+//         },
+//         stringEquals: (row, value) => {
+//             const aI = (row * fieldCount + index) * 2;
+//             const s = tokens[aI];
+//             if (!value) return presence(row) !== Data.ValuePresence.Present;
+//             const len = value.length;
+//             if (len !== tokens[aI + 1] - s) return false;
+//             for (let i = 0; i < len; i++) {
+//                 if (data.charCodeAt(i + s) !== value.charCodeAt(i)) return false;
+//             }
+//             return true;
+//         },
+//         toStringArray: (startRow, endRowExclusive, ctor) => {
+//             const count = endRowExclusive - startRow;
+//             const ret = ctor(count) as any;
+//             for (let i = 0; i < count; i++) { ret[i] = str(startRow + i); }
+//             return ret;
+//         },
+//         toIntArray: (startRow, endRowExclusive, ctor) => {
+//             const count = endRowExclusive - startRow;
+//             const ret = ctor(count) as any;
+//             for (let i = 0; i < count; i++) { ret[i] = int(startRow + i); }
+//             return ret;
+//         },
+//         toFloatArray: (startRow, endRowExclusive, ctor) => {
+//             const count = endRowExclusive - startRow;
+//             const ret = ctor(count) as any;
+//             for (let i = 0; i < count; i++) { ret[i] = float(startRow + i); }
+//             return ret;
+//         }
+//     }
+// }
\ No newline at end of file
diff --git a/src/reader/common/text/column/fixed.ts b/src/reader/common/text/column/fixed.ts
new file mode 100644
index 000000000..e7df1e074
--- /dev/null
+++ b/src/reader/common/text/column/fixed.ts
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Column, ColumnType, createArray } from '../../column'
+import { trimStr } from '../tokenizer'
+import { parseIntSkipLeadingWhitespace, parseFloatSkipLeadingWhitespace } from '../number-parser'
+
+export interface FixedColumnInfo {
+    data: string,
+    lines: ArrayLike<number>,
+    rowCount: number
+}
+
+export default function FixedColumnProvider(info: FixedColumnInfo) {
+    return function<T extends ColumnType>(offset: number, width: number, type: T) {
+        return FixedColumn(info, offset, width, type);
+    }
+}
+
+function getArrayValues(value: (row: number) => any, target: any[], start: number) {
+    for (let i = 0, _e = target.length; i < _e; i++) target[i] = value(start + i);
+    return target;
+}
+
+export function FixedColumn<T extends ColumnType>(info: FixedColumnInfo, offset: number, width: number, type: T): Column<T['@type']> {
+    const { data, lines, rowCount } = info;
+    const { kind } = type;
+
+    const value: Column<T['@type']>['value'] = kind === 'str' ? row => {
+        let s = lines[2 * row] + offset, e = s + width, le = lines[2 * row + 1];
+        if (s >= le) return '';
+        if (e > le) e = le;
+        return trimStr(data, s, e);
+    } : kind === 'int' ? row => {
+        const s = lines[2 * row] + offset, e = s + width;
+        return parseIntSkipLeadingWhitespace(data, s, e);
+    } : row => {
+        const s = lines[2 * row] + offset, e = s + width;
+        return parseFloatSkipLeadingWhitespace(data, s, e);
+    }
+    return {
+        isColumnDefined: true,
+        rowCount,
+        value,
+        toArray(ctor, s, e) {
+            const { array, start } = createArray(rowCount, ctor, s, e);
+            return getArrayValues(value, array, start);
+        }
+    };
+}
\ No newline at end of file
diff --git a/src/reader/common/text/token-field.ts b/src/reader/common/text/token-field.ts
deleted file mode 100644
index 849d7cb84..000000000
--- a/src/reader/common/text/token-field.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import * as Data from '../../../data/data'
-import { parseInt as fastParseInt, parseFloat as fastParseFloat } from './number-parser'
-import { Tokens } from './tokenizer'
-import ShortStringPool from '../../../utils/short-string-pool'
-
-export function createTokenFields(data: string, fields: string[], tokens: Tokens): { [name: string]: Data.Field } {
-    const fi: TokenFieldInfo = { data, fieldCount: fields.length, tokens: tokens.indices };
-    const categoryFields = Object.create(null);
-    for (let i = 0; i < fi.fieldCount; ++i) {
-        categoryFields[fields[i]] = TokenField(fi, i);
-    }
-    return categoryFields;
-}
-
-export interface TokenFieldInfo {
-    data: string,
-    tokens: ArrayLike<number>,
-    fieldCount: number,
-    isCif?: boolean
-}
-
-export function TokenField(info: TokenFieldInfo, index: number): Data.Field {
-    const { data, tokens, fieldCount, isCif = false } = info;
-    const stringPool = ShortStringPool.create();
-
-    const str: Data.Field['str'] = isCif ? row => {
-        const i = (row * fieldCount + index) * 2;
-        const ret = ShortStringPool.get(stringPool, data.substring(tokens[i], tokens[i + 1]));
-        if (ret === '.' || ret === '?') return null;
-        return ret;
-    } : row => {
-        const i = (row * fieldCount + index) * 2;
-        return ShortStringPool.get(stringPool, data.substring(tokens[i], tokens[i + 1]));
-    };
-
-    const int: Data.Field['int'] = row => {
-        const i = (row * fieldCount + index) * 2;
-        return fastParseInt(data, tokens[i], tokens[i + 1]) || 0;
-    };
-
-    const float: Data.Field['float'] = row => {
-        const i = (row * fieldCount + index) * 2;
-        return fastParseFloat(data, tokens[i], tokens[i + 1]) || 0;
-    };
-
-    const presence: Data.Field['presence'] = isCif ? row => {
-        const i = 2 * (row * fieldCount + index);
-        const s = tokens[i];
-        if (tokens[i + 1] - s !== 1) return Data.ValuePresence.Present;
-        const v = data.charCodeAt(s);
-        if (v === 46 /* . */) return Data.ValuePresence.NotSpecified;
-        if (v === 63 /* ? */) return Data.ValuePresence.Unknown;
-        return Data.ValuePresence.Present;
-    } : row => {
-        const i = 2 * (row * fieldCount + index);
-        return tokens[i] === tokens[i + 1] ? Data.ValuePresence.NotSpecified : Data.ValuePresence.Present
-    };
-
-    return {
-        isDefined: true,
-        str,
-        int,
-        float,
-        value: str,
-        presence,
-        areValuesEqual: (rowA, rowB) => {
-            const aI = (rowA * fieldCount + index) * 2, aS = tokens[aI];
-            const bI = (rowB * fieldCount + index) * 2, bS = tokens[bI];
-            const len = tokens[aI + 1] - aS;
-            if (len !== tokens[bI + 1] - bS) return false;
-            for (let i = 0; i < len; i++) {
-                if (data.charCodeAt(i + aS) !== data.charCodeAt(i + bS)) {
-                    return false;
-                }
-            }
-            return true;
-        },
-        stringEquals: (row, value) => {
-            const aI = (row * fieldCount + index) * 2;
-            const s = tokens[aI];
-            if (!value) return presence(row) !== Data.ValuePresence.Present;
-            const len = value.length;
-            if (len !== tokens[aI + 1] - s) return false;
-            for (let i = 0; i < len; i++) {
-                if (data.charCodeAt(i + s) !== value.charCodeAt(i)) return false;
-            }
-            return true;
-        },
-        toStringArray: (startRow, endRowExclusive, ctor) => {
-            const count = endRowExclusive - startRow;
-            const ret = ctor(count) as any;
-            for (let i = 0; i < count; i++) { ret[i] = str(startRow + i); }
-            return ret;
-        },
-        toIntArray: (startRow, endRowExclusive, ctor) => {
-            const count = endRowExclusive - startRow;
-            const ret = ctor(count) as any;
-            for (let i = 0; i < count; i++) { ret[i] = int(startRow + i); }
-            return ret;
-        },
-        toFloatArray: (startRow, endRowExclusive, ctor) => {
-            const count = endRowExclusive - startRow;
-            const ret = ctor(count) as any;
-            for (let i = 0; i < count; i++) { ret[i] = float(startRow + i); }
-            return ret;
-        }
-    }
-}
\ No newline at end of file
diff --git a/src/reader/common/text/tokenizer.ts b/src/reader/common/text/tokenizer.ts
index 79cabe100..b957a35b1 100644
--- a/src/reader/common/text/tokenizer.ts
+++ b/src/reader/common/text/tokenizer.ts
@@ -6,7 +6,7 @@
  * @author Alexander Rose <alexander.rose@weirdbyte.de>
  */
 
-export interface State<Info = any, TokenType = any> {
+export interface State<TokenType = any> {
     data: string
 
     position: number
@@ -16,12 +16,10 @@ export interface State<Info = any, TokenType = any> {
     currentTokenStart: number
     currentTokenEnd: number
 
-    currentTokenType: TokenType,
-
-    info: Info
+    currentTokenType: TokenType
 }
 
-export function State<Info, TokenType>(data: string, info?: Info, initialTokenType?: TokenType): State<Info, TokenType> {
+export function State<TokenType>(data: string, initialTokenType?: TokenType): State<TokenType> {
     return {
         data,
         position: 0,
@@ -29,37 +27,53 @@ export function State<Info, TokenType>(data: string, info?: Info, initialTokenTy
         currentLineNumber: 1,
         currentTokenStart: 0,
         currentTokenEnd: 0,
-        currentTokenType: initialTokenType!,
-        info: info!
+        currentTokenType: initialTokenType!
     };
 }
 
+export function getTokenString(state: State) {
+    return state.data.substring(state.currentTokenStart, state.currentTokenEnd);
+}
+
 /**
  * Eat everything until a newline occurs.
  */
 export function eatLine(state: State) {
+    const { data } = state;
     while (state.position < state.length) {
-        switch (state.data.charCodeAt(state.position)) {
+        switch (data.charCodeAt(state.position)) {
             case 10: // \n
-                state.currentTokenEnd = state.position
-                ++state.position
-                ++state.currentLineNumber
-                return
+                state.currentTokenEnd = state.position;
+                ++state.position;
+                ++state.currentLineNumber;
+                return;
             case 13: // \r
-                state.currentTokenEnd = state.position
-                ++state.position
-                ++state.currentLineNumber
-                if (state.data.charCodeAt(state.position) === 10) {
-                    ++state.position
+                state.currentTokenEnd = state.position;
+                ++state.position;
+                ++state.currentLineNumber;
+                if (data.charCodeAt(state.position) === 10) {
+                    ++state.position;
                 }
-                return
+                return;
             default:
-                ++state.position
+                ++state.position;
+                break;
         }
     }
     state.currentTokenEnd = state.position;
 }
 
+/** Sets the current token start to the current position */
+export function markStart(state: State) {
+    state.currentTokenStart = state.position;
+}
+
+/** Sets the current token start to current position and moves to the next line. */
+export function markLine(state: State) {
+    state.currentTokenStart = state.position;
+    eatLine(state);
+}
+
 /**
  * Eat everything until a whitespace/newline occurs.
  */
@@ -129,6 +143,15 @@ export function trim(state: State, start: number, end: number) {
     state.position = end;
 }
 
+export function trimStr(data: string, start: number, end: number) {
+    let s = start, e = end - 1;
+    let c = data.charCodeAt(s);
+    while ((c === 9 || c === 32) && s <= e) c = data.charCodeAt(++s);
+    c = data.charCodeAt(e);
+    while ((c === 9 || c === 32) && e >= s) c = data.charCodeAt(--e);
+    return data.substring(s, e + 1);
+}
+
 export interface Tokens {
     indicesLenMinus2: number,
     count: number,
diff --git a/src/reader/gro/format.ts b/src/reader/gro/format.ts
deleted file mode 100644
index ce24a7978..000000000
--- a/src/reader/gro/format.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import schema from './schema'
-import parse from './parser'
-
-export default {
-    parse,
-    schema
-};
\ No newline at end of file
diff --git a/src/reader/gro/parser.ts b/src/reader/gro/parser.ts
index 7c41e81bb..f4560630e 100644
--- a/src/reader/gro/parser.ts
+++ b/src/reader/gro/parser.ts
@@ -5,77 +5,71 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import { State as TokenizerState, Tokens, eatLine, skipWhitespace, eatValue, trim } from '../common/text/tokenizer'
-import { parseInt } from '../common/text/number-parser'
-import { createTokenFields } from '../common/text/token-field'
-import * as Data from '../../data/data'
+import { State as TokenizerState, Tokens, markLine, getTokenString } from '../common/text/tokenizer'
+import FixedColumn from '../common/text/column/fixed'
+import { ColumnType, UndefinedColumn } from '../common/column'
+import * as Schema from './schema'
 import Result from '../result'
 
-interface StateInfo {
-    numberOfAtoms: number
-    hasVelocities: boolean
-    numberOfDecimalPlaces: number
+interface State {
+    tokenizer: TokenizerState,
+    header: Schema.Header,
+    numberOfAtoms: number,
 }
 
-type State = TokenizerState<StateInfo>
+function createEmptyHeader(): Schema.Header {
+    return {
+        title: '',
+        timeInPs: 0,
+        hasVelocities: false,
+        precision: { position: 0, velocity: 0 },
+        box: [0, 0, 0]
+    };
+}
 
-function createState(data: string): State {
-    return TokenizerState(data, { numberOfAtoms: 0, hasVelocities: false, numberOfDecimalPlaces: 3 });
+function createState(tokenizer: TokenizerState): State {
+    return {
+        tokenizer,
+        header: createEmptyHeader(),
+        numberOfAtoms: 0
+    };
 }
 
 /**
  * title string (free format string, optional time in ps after 't=')
  */
-function handleTitleString(state: State, tokens: Tokens) {
-    eatLine(state)
-    // console.log('title', state.data.substring(state.currentTokenStart, state.currentTokenEnd))
-    let start = state.currentTokenStart
-    let end = state.currentTokenEnd
-    let valueStart = state.currentTokenStart
-    let valueEnd = start
-
-    while (valueEnd < end && !isTime(state.data, valueEnd)) ++valueEnd;
+function handleTitleString(state: State) {
+    const { tokenizer, header } = state;
+    markLine(tokenizer);
 
-    if (isTime(state.data, valueEnd)) {
-        let timeStart = valueEnd + 2
+    let line = getTokenString(tokenizer);
 
-        while (valueEnd > start && isSpaceOrComma(state.data, valueEnd - 1)) --valueEnd;
-        Tokens.add(tokens, valueStart, valueEnd)  // title
+    // skip potential empty lines...
+    if (line.trim().length === 0) {
+        markLine(tokenizer);
+        line = getTokenString(tokenizer);
+    }
 
-        while (timeStart < end && state.data.charCodeAt(timeStart) === 32) ++timeStart;
-        while (valueEnd > timeStart && state.data.charCodeAt(valueEnd - 1) === 32) --valueEnd;
-        Tokens.add(tokens, timeStart, end)  // time
+    const timeOffset = line.lastIndexOf('t=');
+    if (timeOffset >= 0) {
+        header.timeInPs = parseFloat(line.substring(timeOffset + 2));
+        header.title = line.substring(0, timeOffset).trim();
+        if (header.title && header.title[header.title.length - 1] === ',') {
+            header.title = header.title.substring(0, header.title.length - 1);
+        }
     } else {
-        Tokens.add(tokens, valueStart, valueEnd)  // title
-        Tokens.add(tokens, valueEnd, valueEnd)  // empty token for time
+        header.title = line;
     }
 }
 
-function isSpaceOrComma(data: string, position: number): boolean {
-    const c = data.charCodeAt(position);
-    return c === 32 || c === 44
-}
-
-function isTime(data: string, position: number): boolean {
-    // T/t
-    const c = data.charCodeAt(position);
-    if (c !== 84 && c !== 116) return false;
-    // =
-    if (data.charCodeAt(position + 1) !== 61) return false;
-
-    return true;
-}
-
 /**
  * number of atoms (free format integer)
  */
-function handleNumberOfAtoms(state: State, tokens: Tokens) {
-    skipWhitespace(state)
-    state.currentTokenStart = state.position
-    eatValue(state)
-    state.info.numberOfAtoms = parseInt(state.data, state.currentTokenStart, state.currentTokenEnd)
-    Tokens.add(tokens, state.currentTokenStart, state.currentTokenEnd)
-    eatLine(state)
+function handleNumberOfAtoms(state: State) {
+    const { tokenizer } = state;
+    markLine(tokenizer);
+    const line = getTokenString(tokenizer);
+    state.numberOfAtoms = parseInt(line);
 }
 
 /**
@@ -94,33 +88,46 @@ function handleNumberOfAtoms(state: State, tokens: Tokens) {
  *     position (in nm, x y z in 3 columns, each 8 positions with 3 decimal places)
  *     velocity (in nm/ps (or km/s), x y z in 3 columns, each 8 positions with 4 decimal places)
  */
-function handleAtoms(state: State) {
-    const fieldSizes = [ 5, 5, 5, 5, 8, 8, 8, 8, 8, 8 ];
-    const fields = [ 'residueNumber', 'residueName', 'atomName', 'atomNumber', 'x', 'y', 'z' ]
-    if (state.info.hasVelocities) {
-        fields.push('vx', 'vy', 'vz')
-    }
-
-    const fieldCount = fields.length
-    const tokens = Tokens.create(state.info.numberOfAtoms * 2 * fieldCount)
+function handleAtoms(state: State): Schema.Atoms {
+    const { tokenizer, numberOfAtoms } = state;
+    const lineTokens = Tokens.create(numberOfAtoms * 2);
 
-    let start: number;
-    let end: number;
-
-    for (let i = 0, _i = state.info.numberOfAtoms; i < _i; ++i) {
-        state.currentTokenStart = state.position;
-        end = state.currentTokenStart;
-        for (let j = 0; j < fieldCount; ++j) {
-            start = end;
-            end = start + fieldSizes[j];
-
-            trim(state, start, end);
-            Tokens.addUnchecked(tokens, state.currentTokenStart, state.currentTokenEnd);
-        }
-        eatLine(state)
+    for (let i = 0; i < numberOfAtoms; i++) {
+        markLine(tokenizer);
+        Tokens.addUnchecked(lineTokens, tokenizer.currentTokenStart, tokenizer.currentTokenEnd);
     }
 
-    return Data.Category(state.info.numberOfAtoms, createTokenFields(state.data, fields, tokens));
+    const lines = lineTokens.indices;
+    const positionSample = tokenizer.data.substring(lines[0], lines[1]).substring(20);
+    const precisions = positionSample.match(/\.\d+/g)!;
+    const hasVelocities = precisions.length === 6;
+    state.header.hasVelocities = hasVelocities;
+    state.header.precision.position = precisions[0].length - 1;
+    state.header.precision.velocity = hasVelocities ? precisions[3].length - 1 : 0;
+
+    const pO = 20;
+    const pW = state.header.precision.position + 5;
+    const vO = pO + 3 * pW;
+    const vW = state.header.precision.velocity + 4;
+
+    const col = FixedColumn({ data: tokenizer.data, lines, rowCount: state.numberOfAtoms });
+    const undef = UndefinedColumn(state.numberOfAtoms, ColumnType.float);
+
+    const ret = {
+        count: state.numberOfAtoms,
+        residueNumber: col(0, 5, ColumnType.int),
+        residueName: col(5, 5, ColumnType.str),
+        atomName: col(10, 5, ColumnType.str),
+        atomNumber: col(15, 5, ColumnType.int),
+        x: col(pO, pW, ColumnType.float),
+        y: col(pO + pW, pW, ColumnType.float),
+        z: col(pO + 2 * pW, pW, ColumnType.float),
+        vx: hasVelocities ? col(vO, vW, ColumnType.float) : undef,
+        vy: hasVelocities ? col(vO + vW, vW, ColumnType.float) : undef,
+        vz: hasVelocities ? col(vO + 2 * vW, vW, ColumnType.float) : undef,
+    };
+
+    return ret;
 }
 
 /**
@@ -129,35 +136,32 @@ function handleAtoms(state: State) {
  * the last 6 values may be omitted (they will be set to zero).
  * Gromacs only supports boxes with v1(y)=v1(z)=v2(z)=0.
  */
-function handleBoxVectors(state: State, tokens: Tokens) {
-    // just read the first three values, ignore any remaining
-    for (let i = 0; i < 3; ++i) {
-        skipWhitespace(state);
-        state.currentTokenStart = state.position;
-        eatValue(state);
-        Tokens.add(tokens, state.currentTokenStart, state.currentTokenEnd);
-    }
+function handleBoxVectors(state: State) {
+    const { tokenizer } = state;
+    markLine(tokenizer);
+    const values = getTokenString(tokenizer).trim().split(/\s+/g);
+    state.header.box = [+values[0], +values[1], +values[2]];
 }
 
-function parseInternal(data: string): Result<Data.File> {
-    const state = createState(data);
-
-    const headerFields = ['title', 'timeInPs', 'numberOfAtoms', 'boxX', 'boxY', 'boxZ'];
-    const headerTokens = Tokens.create(2 * headerFields.length);
-
-    handleTitleString(state, headerTokens);
-    handleNumberOfAtoms(state, headerTokens);
-    const atoms = handleAtoms(state);
-    handleBoxVectors(state, headerTokens);
-
-    const block = Data.Block({
-        header: Data.Category(1, createTokenFields(data, headerFields, headerTokens)),
-        atoms
-    });
+function parseInternal(data: string): Result<Schema.File> {
+    const tokenizer = TokenizerState(data);
+
+    const structures: Schema.Structure[] = [];
+    while (tokenizer.position < data.length) {
+        const state = createState(tokenizer);
+        handleTitleString(state);
+        handleNumberOfAtoms(state);
+        const atoms = handleAtoms(state);
+        handleBoxVectors(state);
+        structures.push({ header: state.header, atoms });
+    }
 
-    return Result.success(Data.File([block]));
+    const result: Schema.File = { structures };
+    return Result.success(result);
 }
 
-export default function parse(data: string) {
+export function parse(data: string) {
     return parseInternal(data);
-}
\ No newline at end of file
+}
+
+export default parse;
\ No newline at end of file
diff --git a/src/reader/gro/schema.d.ts b/src/reader/gro/schema.d.ts
new file mode 100644
index 000000000..1d49d9641
--- /dev/null
+++ b/src/reader/gro/schema.d.ts
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Alexander Rose <alexander.rose@weirdbyte.de>
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { Column } from '../common/column'
+
+export interface Header {
+    title: string,
+    timeInPs: number,
+    /** number of decimal places */
+    precision: { position: number, velocity: number },
+    hasVelocities: boolean,
+    box: [number, number, number]
+}
+
+export interface Atoms {
+    count: number,
+    residueNumber: Column<number>,
+    residueName: Column<string>,
+    atomName: Column<string>,
+    atomNumber: Column<number>,
+    x: Column<number>,
+    y: Column<number>,
+    z: Column<number>,
+    vx: Column<number>,
+    vy: Column<number>,
+    vz: Column<number>
+}
+
+export interface Structure {
+    header: Readonly<Header>,
+    atoms: Readonly<Atoms>
+}
+
+export interface File {
+    structures: Structure[]
+}
\ No newline at end of file
diff --git a/src/reader/gro/schema.ts b/src/reader/gro/schema.ts
deleted file mode 100644
index d8e9c576a..000000000
--- a/src/reader/gro/schema.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2017 molio contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- * @author David Sehnal <david.sehnal@gmail.com>
- */
-
-import * as Schema from '../../data/schema'
-import * as Data from '../../data/data'
-
-const str = Schema.Field.str()
-const int = Schema.Field.int()
-const float = Schema.Field.float()
-
-const header = {
-    'title': str,
-    'timeInPs': float,
-    'numberOfAtoms': int,
-    'boxX': float,
-    'boxY': float,
-    'boxZ': float
-}
-
-const atoms = {
-    'residueNumber': int,
-    'residueName': str,
-    'atomName': str,
-    'atomNumber': int,
-    'x': float,
-    'y': float,
-    'z': float,
-    'vx': float,
-    'vy': float,
-    'vz': float
-}
-
-const schema = { header, atoms };
-export default function (block: Data.Block) {
-    return Schema.apply(schema, block);
-}
\ No newline at end of file
diff --git a/src/data/spec/schema.spec.ts b/src/reader/spec/cif.spec.ts
similarity index 95%
rename from src/data/spec/schema.spec.ts
rename to src/reader/spec/cif.spec.ts
index 131468eb1..bbd81a321 100644
--- a/src/data/spec/schema.spec.ts
+++ b/src/reader/spec/cif.spec.ts
@@ -4,8 +4,8 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import * as Data from '../data'
-import * as Schema from '../schema'
+import * as Data from '../cif/data'
+import * as Schema from '../cif/schema'
 
 function Field(values: any[]): Data.Field {
     return {
@@ -13,7 +13,6 @@ function Field(values: any[]): Data.Field {
         str: row => '' + values[row],
         int: row => +values[row] || 0,
         float: row => +values[row] || 0,
-        value: row => values[row],
 
         presence: row => Data.ValuePresence.Present,
         areValuesEqual: (rowA, rowB) => values[rowA] === values[rowB],
diff --git a/src/reader/spec/gro.spec.ts b/src/reader/spec/gro.spec.ts
index dc2423731..67dd4b21d 100644
--- a/src/reader/spec/gro.spec.ts
+++ b/src/reader/spec/gro.spec.ts
@@ -5,7 +5,7 @@
  * @author David Sehnal <david.sehnal@gmail.com>
  */
 
-import Gro from '../gro/format'
+import Gro from '../gro/parser'
 
 const groString = `MD of 2 waters, t= 4.2
     6
@@ -15,82 +15,77 @@ const groString = `MD of 2 waters, t= 4.2
     2WATER  OW1    4   1.275   0.053   0.622  0.2519  0.3140 -0.1734
     2WATER  HW2    5   1.337   0.002   0.680 -1.0641 -1.1349  0.0257
     2WATER  HW3    6   1.326   0.120   0.568  1.9427 -0.8216 -0.0244
-   1.82060   1.82060   1.82060`
+   1.82060   2.82060   3.82060`
 
 const groStringHighPrecision = `Generated by trjconv : 2168 system t=  15.00000
     3
     1ETH     C1    1   2.735383   2.672010   1.450194  0.2345 -0.1622 0.2097
     1ETH    H11    2   0.015804   2.716597   1.460588  0.8528 -0.7984 0.6605
     1ETH    H12    3   2.744822   2.565544   1.409227 -2.3812  2.8618 1.8101
-   1.82060   1.82060   1.82060`
+   1.82060   2.82060   3.82060`
 
 describe('gro reader', () => {
     it('basic', () => {
-        const parsed = Gro.parse(groString)
+        const parsed = Gro(groString)
 
         if (parsed.isError) {
             console.log(parsed)
-        } else {
-            const groFile = parsed.result;
-            const data = Gro.schema(groFile.blocks[0]);
-
-            const { header, atoms } = data;
-            if (header._isDefined) {
-                expect(header.title.value(0)).toBe('MD of 2 waters')
-                expect(header.timeInPs.value(0)).toBeCloseTo(4.2)
-                expect(header.numberOfAtoms.value(0)).toBe(6)
-
-                expect(header.boxX.value(0)).toBeCloseTo(1.82060)
-                expect(header.boxY.value(0)).toBeCloseTo(1.82060)
-                expect(header.boxZ.value(0)).toBeCloseTo(1.82060)
-            } else {
-                console.error('no header')
-            }
-
-            if (atoms._rowCount === 6)  {
-                expect(atoms.x.value(0)).toBeCloseTo(0.126);
-                expect(atoms.y.value(0)).toBeCloseTo(1.624);
-                expect(atoms.z.value(0)).toBeCloseTo(1.679);
-
-                // TODO: check velocities when they are parsed.
-            } else {
-                console.error('no atoms');
-            }
+            return;
         }
-    })
+
+        const groFile = parsed.result;
+        const data = groFile.structures[0];
+
+        const { header, atoms } = data;
+        expect(header.title).toBe('MD of 2 waters')
+        expect(header.timeInPs).toBeCloseTo(4.2)
+        expect(header.hasVelocities).toBe(true);
+        expect(header.precision.position).toBe(3);
+        expect(header.precision.velocity).toBe(4);
+        expect(header.box[0]).toBeCloseTo(1.82060, 0.00001)
+        expect(header.box[1]).toBeCloseTo(2.82060, 0.00001)
+        expect(header.box[2]).toBeCloseTo(3.82060, 0.00001)
+
+        expect(atoms.count).toBe(6);
+
+        expect(atoms.x.value(0)).toBeCloseTo(0.126, 0.001);
+        expect(atoms.y.value(0)).toBeCloseTo(1.624, 0.001);
+        expect(atoms.z.value(0)).toBeCloseTo(1.679, 0.001);
+
+        expect(atoms.vx.value(5)).toBeCloseTo(1.9427, 0.0001);
+        expect(atoms.vy.value(5)).toBeCloseTo(-0.8216, 0.0001);
+        expect(atoms.vz.value(5)).toBeCloseTo(-0.0244, 0.0001);
+    });
 
     it('high precision', () => {
-        const parsed = Gro.parse(groStringHighPrecision)
+        const parsed = Gro(groStringHighPrecision);
 
         if (parsed.isError) {
             console.log(parsed)
-        } else {
-            const groFile = parsed.result;
-            const data = Gro.schema(groFile.blocks[0]);
-
-            const { header, atoms } = data;
-            if (header._isDefined) {
-                expect(header.title.value(0)).toBe('Generated by trjconv : 2168 system')
-                expect(header.timeInPs.value(0)).toBeCloseTo(15)
-                expect(header.numberOfAtoms.value(0)).toBe(3)
-
-                expect(header.boxX.value(0)).toBeCloseTo(1.82060)
-                expect(header.boxY.value(0)).toBeCloseTo(1.82060)
-                expect(header.boxZ.value(0)).toBeCloseTo(1.82060)
-            } else {
-                console.error('no header')
-            }
-
-            if (atoms._rowCount === 3)  {
-                // TODO: test when high-prec parser is available
-                // expect(atoms.x.value(1)).toBeCloseTo(0.015804, 0.00001);
-                // expect(atoms.y.value(1)).toBeCloseTo(2.716597, 0.00001);
-                // expect(atoms.z.value(1)).toBeCloseTo(1.460588, 0.00001);
-
-                // TODO: check velocities when they are parsed.
-            } else {
-                console.error('no atoms');
-            }
+            return;
         }
-    })
+
+        const groFile = parsed.result;
+        const data = groFile.structures[0];
+
+        const { header, atoms } = data;
+        expect(header.title).toBe('Generated by trjconv : 2168 system')
+        expect(header.timeInPs).toBeCloseTo(15)
+        expect(header.hasVelocities).toBe(true);
+        expect(header.precision.position).toBe(6);
+        expect(header.precision.velocity).toBe(4);
+        expect(header.box[0]).toBeCloseTo(1.82060, 0.00001)
+        expect(header.box[1]).toBeCloseTo(2.82060, 0.00001)
+        expect(header.box[2]).toBeCloseTo(3.82060, 0.00001)
+
+        expect(atoms.count).toBe(3);
+
+        expect(atoms.x.value(1)).toBeCloseTo(0.015804, 0.000001);
+        expect(atoms.y.value(1)).toBeCloseTo(2.716597, 0.000001);
+        expect(atoms.z.value(1)).toBeCloseTo(1.460588, 0.000001);
+
+        expect(atoms.vx.value(0)).toBeCloseTo(0.2345, 0.0001);
+        expect(atoms.vy.value(0)).toBeCloseTo(-0.1622, 0.0001);
+        expect(atoms.vz.value(0)).toBeCloseTo(0.2097, 0.0001);
+    });
 });
diff --git a/src/script.ts b/src/script.ts
index 2febe153c..92b27d329 100644
--- a/src/script.ts
+++ b/src/script.ts
@@ -7,72 +7,64 @@
 // import * as util from 'util'
 import * as fs from 'fs'
 
-import Gro from './reader/gro/format'
+import Gro from './reader/gro/parser'
 
 //const file = '1crn.gro'
 // const file = 'water.gro'
 // const file = 'test.gro'
 const file = 'md_1u19_trj.gro'
 
-fs.readFile(`./examples/${file}`, 'utf8', function (err,data) {
+fs.readFile(`./examples/${file}`, 'utf8', function (err,input) {
     if (err) {
         return console.log(err);
     }
     // console.log(data);
 
     console.time('parse')
-    const parsed = Gro.parse(data)
+    const parsed = Gro(input)
     console.timeEnd('parse')
     if (parsed.isError) {
         console.log(parsed)
-    } else {
-        const groFile = parsed.result
-        const data = Gro.schema(groFile.blocks[0])
+        return;
+    }
 
-        // const header = groFile.blocks[0].getCategory('header')
-        const { header, atoms } = data;
-        if (header._rowCount !== 1) {
-            console.log('title', header.title.value(0))
-            console.log('timeInPs', header.timeInPs.value(0))
-            console.log('numberOfAtoms', header.numberOfAtoms.value(0))
-            console.log('boxX', header.boxX.value(0))
-            console.log('boxY', header.boxY.value(0))
-            console.log('boxZ', header.boxZ.value(0))
-        } else {
-            console.error('no header')
-        }
+    const groFile = parsed.result
 
-        if (atoms._rowCount > 0) {
-            console.log(`'${atoms.residueNumber.value(1)}'`)
-            console.log(`'${atoms.residueName.value(1)}'`)
-            console.log(`'${atoms.atomName.value(1)}'`)
-            console.log(atoms.z.value(1))
-            console.log(`'${atoms.z.value(1)}'`)
+    console.log('structure count: ', groFile.structures.length);
 
-            const n = atoms._rowCount
-            console.log('rowCount', n)
+    const data = groFile.structures[0];
 
-            console.time('getFloatArray x')
-            const x = atoms.x.toArray(0, n, x => new Float32Array(x))!
-            console.timeEnd('getFloatArray x')
-            console.log(x.length, x[0], x[x.length-1])
+    // const header = groFile.blocks[0].getCategory('header')
+    const { header, atoms } = data;
+    console.log(JSON.stringify(header, null, 2));
+    console.log('number of atoms:', atoms.count);
 
-            console.time('getFloatArray y')
-            const y = atoms.y.toArray(0, n, x => new Float32Array(x))!
-            console.timeEnd('getFloatArray y')
-            console.log(y.length, y[0], y[y.length-1])
+    console.log(`'${atoms.residueNumber.value(1)}'`)
+    console.log(`'${atoms.residueName.value(1)}'`)
+    console.log(`'${atoms.atomName.value(1)}'`)
+    console.log(atoms.z.value(1))
+    console.log(`'${atoms.z.value(1)}'`)
 
-            console.time('getFloatArray z')
-            const z = atoms.z.toArray(0, n, x => new Float32Array(x))!
-            console.timeEnd('getFloatArray z')
-            console.log(z.length, z[0], z[z.length-1])
+    const n = atoms.count;
+    console.log('rowCount', n)
 
-            console.time('getIntArray residueNumber')
-            const residueNumber = atoms.residueNumber.toArray(0, n, x => new Int32Array(x))!
-            console.timeEnd('getIntArray residueNumber')
-            console.log(residueNumber.length, residueNumber[0], residueNumber[residueNumber.length-1])
-        } else {
-            console.error('no atoms')
-        }
-    }
+    console.time('getFloatArray x')
+    const x = atoms.x.toArray(x => new Float32Array(x))!
+    console.timeEnd('getFloatArray x')
+    console.log(x.length, x[0], x[x.length-1])
+
+    console.time('getFloatArray y')
+    const y = atoms.y.toArray(x => new Float32Array(x))!
+    console.timeEnd('getFloatArray y')
+    console.log(y.length, y[0], y[y.length-1])
+
+    console.time('getFloatArray z')
+    const z = atoms.z.toArray(x => new Float32Array(x))!
+    console.timeEnd('getFloatArray z')
+    console.log(z.length, z[0], z[z.length-1])
+
+    console.time('getIntArray residueNumber')
+    const residueNumber = atoms.residueNumber.toArray(x => new Int32Array(x))!
+    console.timeEnd('getIntArray residueNumber')
+    console.log(residueNumber.length, residueNumber[0], residueNumber[residueNumber.length-1])
 });
-- 
GitLab