@ccp-nc/crystvis-js 0.4.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +16 -0
- package/.github/workflows/test-mocha.yml +30 -0
- package/.vscode/settings.json +4 -0
- package/LICENSE +21 -0
- package/README.html +1127 -0
- package/README.md +76 -0
- package/demo/demo.css +30 -0
- package/demo/index.html +76 -0
- package/demo/main.js +143 -0
- package/docs/.nojekyll +0 -0
- package/docs-tutorials/Events.md +57 -0
- package/docs-tutorials/Queries.md +50 -0
- package/fonts/Rubik/OFL.txt +93 -0
- package/fonts/Rubik/README.txt +77 -0
- package/fonts/Rubik/Rubik-Italic-VariableFont_wght.ttf +0 -0
- package/fonts/Rubik/Rubik-VariableFont_wght.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Black.ttf +0 -0
- package/fonts/Rubik/static/Rubik-BlackItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Bold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-BoldItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-ExtraBold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-ExtraBoldItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Italic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Light.ttf +0 -0
- package/fonts/Rubik/static/Rubik-LightItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Medium.ttf +0 -0
- package/fonts/Rubik/static/Rubik-MediumItalic.ttf +0 -0
- package/fonts/Rubik/static/Rubik-Regular.ttf +0 -0
- package/fonts/Rubik/static/Rubik-SemiBold.ttf +0 -0
- package/fonts/Rubik/static/Rubik-SemiBoldItalic.ttf +0 -0
- package/index.html +25 -0
- package/index.js +11 -0
- package/jsconf.json +14 -0
- package/lib/assets/fonts/Rubik-Medium.fnt +297 -0
- package/lib/assets/fonts/Rubik-Medium.png +0 -0
- package/lib/assets/fonts/bmpfonts.in.js +16 -0
- package/lib/assets/fonts/bmpfonts.js +9 -0
- package/lib/assets/fonts/font.js +82 -0
- package/lib/assets/fonts/index.js +14 -0
- package/lib/assets/fonts/threebmfont.js +28 -0
- package/lib/data.js +125 -0
- package/lib/formats/cell.js +114 -0
- package/lib/formats/cif.js +22 -0
- package/lib/formats/magres.js +337 -0
- package/lib/formats/xyz.js +124 -0
- package/lib/loader.js +87 -0
- package/lib/model.js +2076 -0
- package/lib/modelview.js +382 -0
- package/lib/nmrdata.js +2898 -0
- package/lib/orbit.js +1233 -0
- package/lib/primitives/atoms.js +261 -0
- package/lib/primitives/cell.js +160 -0
- package/lib/primitives/dither.js +156 -0
- package/lib/primitives/ellipsoid.js +183 -0
- package/lib/primitives/geometries.js +20 -0
- package/lib/primitives/index.js +48 -0
- package/lib/primitives/isosurface.js +171 -0
- package/lib/primitives/shapes.js +100 -0
- package/lib/primitives/sprites.js +172 -0
- package/lib/query.js +158 -0
- package/lib/render.js +440 -0
- package/lib/selbox.js +361 -0
- package/lib/shaders/aura.frag +26 -0
- package/lib/shaders/aura.vert +37 -0
- package/lib/shaders/dither.frag +42 -0
- package/lib/shaders/dither.vert +8 -0
- package/lib/shaders/index.in.js +17 -0
- package/lib/shaders/index.js +25 -0
- package/lib/shaders/msdf300.frag +25 -0
- package/lib/shaders/msdf300.vert +45 -0
- package/lib/tensor.js +227 -0
- package/lib/utils.js +168 -0
- package/lib/visualizer.js +480 -0
- package/package.json +106 -0
- package/scripts/build-bundle.js +17 -0
- package/scripts/build-fonts.js +43 -0
- package/scripts/build-resources.js +46 -0
- package/scripts/plugins-shim.js +10 -0
- package/test/chemdata.js +69 -0
- package/test/data/CHA.cif +74 -0
- package/test/data/H2O.xyz +8 -0
- package/test/data/H2_bound.xyz +4 -0
- package/test/data/ethanol.cell +25 -0
- package/test/data/ethanol.magres +238 -0
- package/test/data/example_single.cif +789 -0
- package/test/data/frac.cell +8 -0
- package/test/data/org.cif +427 -0
- package/test/data/pyridine.xyz +13 -0
- package/test/data/si8.xyz +10 -0
- package/test/loader.js +107 -0
- package/test/model.js +368 -0
- package/test/query.js +135 -0
- package/test/tensor.js +133 -0
- package/test/test-html/examples.js +1485 -0
- package/test/test-html/index.html +33 -0
- package/test/test-html/index.js +279 -0
- package/tools/compile_colors.py +120 -0
- package/tools/compile_periodic.py +96 -0
- package/tools/ptable.json +497 -0
- package/tools/test +5844 -0
package/lib/data.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
PeriodicTable as PeriodicTable
|
|
5
|
+
} from 'mendeleev';
|
|
6
|
+
|
|
7
|
+
import nmrData from './nmrdata.js';
|
|
8
|
+
import { shiftCpkColor } from './utils.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @fileoverview Various data arrays and structures storing useful information
|
|
12
|
+
* @private
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// Van der Waals radii by atomic number
|
|
16
|
+
const vdwRadii = [1.77, // Z = 0 is used as the default
|
|
17
|
+
1.2, 1.4, 1.82, 1.7, 2.08,
|
|
18
|
+
1.95, 1.55, 1.7, 1.73, 1.54, 2.27, 1.73, 2.05,
|
|
19
|
+
2.1, 2.08, 2.0, 1.97, 1.88, 2.75, 1.973, 1.7,
|
|
20
|
+
1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.63, 1.4, 1.39,
|
|
21
|
+
1.87, 1.7, 1.85, 1.9, 2.1, 2.02, 1.7, 1.7, 1.7,
|
|
22
|
+
1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.63, 1.72, 1.58,
|
|
23
|
+
1.93, 2.17, 2.2, 2.06, 2.15, 2.16, 1.7, 1.7,
|
|
24
|
+
1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7,
|
|
25
|
+
1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7,
|
|
26
|
+
1.7, 1.7, 1.7, 1.72, 1.66, 1.55, 1.96, 2.02,
|
|
27
|
+
1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7,
|
|
28
|
+
1.86, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7, 1.7,
|
|
29
|
+
1.7, 1.7, 1.7
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const cpkColors = [0xff1493, // Z = 0 is used as the default
|
|
33
|
+
0xffffff, 0xd9ffff, 0xcc80ff, 0xc2ff00, 0xffb5b5, 0x909090, 0x3050f8, 0xff0d0d,
|
|
34
|
+
0x90e050, 0xb3e3f5, 0xab5cf2, 0x8aff00, 0xbfa6a6, 0xf0c8a0, 0xff8000, 0xffff30,
|
|
35
|
+
0x1ff01f, 0x80d1e3, 0x8f40d4, 0x3dff00, 0xe6e6e6, 0xbfc2c7, 0xa6a6ab, 0x8a99c7,
|
|
36
|
+
0x9c7ac7, 0xe06633, 0xf090a0, 0x50d050, 0xc88033, 0x7d80b0, 0xc28f8f, 0x668f8f,
|
|
37
|
+
0xbd80e3, 0xffa100, 0xa62929, 0x5cb8d1, 0x702eb0, 0x00ff00, 0x94ffff, 0x94e0e0,
|
|
38
|
+
0x73c2c9, 0x54b5b5, 0x3b9e9e, 0x248f8f, 0x0a7d8c, 0x006985, 0xc0c0c0, 0xffd98f,
|
|
39
|
+
0xa67573, 0x668080, 0x9e63b5, 0xd47a00, 0x940094, 0x429eb0, 0x57178f, 0x00c900,
|
|
40
|
+
0x70d4ff, 0xffffc7, 0xd9ffc7, 0xc7ffc7, 0xa3ffc7, 0x8fffc7, 0x61ffc7, 0x45ffc7,
|
|
41
|
+
0x30ffc7, 0x1fffc7, 0x00ff9c, 0x00e675, 0x00d452, 0x00bf38, 0x00ab24, 0x4dc2ff,
|
|
42
|
+
0x4da6ff, 0x2194d6, 0x267dab, 0x266696, 0x175487, 0xd0d0e0, 0xffd123, 0xb8b8d0,
|
|
43
|
+
0xa6544d, 0x575961, 0x9e4fb5, 0xab5c00, 0x754f45, 0x428296, 0x420066, 0x007d00,
|
|
44
|
+
0x70abfa, 0x00baff, 0x00a1ff, 0x008fff, 0x0080ff, 0x006bff, 0x545cf2, 0x785ce3,
|
|
45
|
+
0x8a4fe3, 0xa136d4, 0xb31fd4, 0xb31fba, 0xb30da6, 0xbd0d87, 0xc70066, 0xcc0059,
|
|
46
|
+
0xd1004f, 0xd90045, 0xe00038, 0xe6002e, 0xeb0026
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
function getVdwRadius(symbol) {
|
|
51
|
+
var el = PeriodicTable.getElement(symbol);
|
|
52
|
+
var Z = (el ? el.number : 0);
|
|
53
|
+
return vdwRadii[Z];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getCpkColor(symbol, isotope=null) {
|
|
57
|
+
var el = PeriodicTable.getElement(symbol);
|
|
58
|
+
var Z = (el ? el.number : 0);
|
|
59
|
+
var cpkc = cpkColors[Z];
|
|
60
|
+
|
|
61
|
+
if (isotope !== null) {
|
|
62
|
+
// We apply an isotope correction
|
|
63
|
+
var edata = nmrData[symbol];
|
|
64
|
+
if (isotope != edata.maxiso) {
|
|
65
|
+
// Then a correction is necessary
|
|
66
|
+
var isolist = getIsotopeList(symbol);
|
|
67
|
+
var imax = isolist.indexOf(edata.maxiso);
|
|
68
|
+
var ic = isolist.indexOf(isotope.toString());
|
|
69
|
+
var shift = (ic-imax)/isolist.length;
|
|
70
|
+
cpkc = shiftCpkColor(cpkc, shift);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return cpkc;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getIsotopeList(symbol) {
|
|
78
|
+
const data = nmrData[symbol];
|
|
79
|
+
if (!data) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// If we do have it though...
|
|
84
|
+
return Object.keys(data.isotopes).sort();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function getElementData(symbol) {
|
|
88
|
+
return nmrData[symbol];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function getIsotopeData(symbol, iso=null) {
|
|
92
|
+
const eldata = nmrData[symbol];
|
|
93
|
+
|
|
94
|
+
if (eldata == null) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (iso === null) {
|
|
99
|
+
// Make it the most common one
|
|
100
|
+
iso = eldata.maxiso;
|
|
101
|
+
}
|
|
102
|
+
else if (iso === 'nmr') {
|
|
103
|
+
iso = eldata.maxiso_NMR;
|
|
104
|
+
}
|
|
105
|
+
else if (iso === 'Q') {
|
|
106
|
+
iso = eldata.maxiso_Q;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (iso === null) {
|
|
110
|
+
// No such isotope
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return eldata.isotopes[iso];
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export {
|
|
118
|
+
vdwRadii,
|
|
119
|
+
cpkColors,
|
|
120
|
+
getVdwRadius,
|
|
121
|
+
getCpkColor,
|
|
122
|
+
getIsotopeList,
|
|
123
|
+
getElementData,
|
|
124
|
+
getIsotopeData
|
|
125
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Function for loading CASTEP's Cell files
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import _ from 'lodash';
|
|
9
|
+
import {
|
|
10
|
+
Atoms
|
|
11
|
+
} from 'crystcif-parse';
|
|
12
|
+
|
|
13
|
+
function cellBlocks(lines, units={}) {
|
|
14
|
+
const block_re = /%BLOCK\s+([A-Z_]+)/;
|
|
15
|
+
const endblock_re = /%ENDBLOCK\s+([A-Z_]+)/;
|
|
16
|
+
|
|
17
|
+
let blocks = {};
|
|
18
|
+
_.forEach(lines, (l, i) => {
|
|
19
|
+
|
|
20
|
+
let lu = l.toUpperCase();
|
|
21
|
+
let ms = block_re.exec(lu);
|
|
22
|
+
let me = endblock_re.exec(lu);
|
|
23
|
+
|
|
24
|
+
if (ms) {
|
|
25
|
+
let name = ms[1].toUpperCase();
|
|
26
|
+
if (name in blocks) {
|
|
27
|
+
throw Error('Duplicated ' + name + ' block found');
|
|
28
|
+
}
|
|
29
|
+
blocks[name] = {start: i};
|
|
30
|
+
} else if (me) {
|
|
31
|
+
let name = me[1].toUpperCase();
|
|
32
|
+
if (!(name in blocks)) {
|
|
33
|
+
throw Error('Block ' + name + ' ends without starting');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
blocks[name]['end'] = i;
|
|
37
|
+
// Assign the contents
|
|
38
|
+
let i0 = blocks[name].start;
|
|
39
|
+
// Identify any units
|
|
40
|
+
let ul = lines[i0+1].trim().toLowerCase();
|
|
41
|
+
if (units[name] && (ul === units[name] || units[name].includes(ul))) {
|
|
42
|
+
i0 += 1;
|
|
43
|
+
blocks[name]['units'] = ul;
|
|
44
|
+
}
|
|
45
|
+
blocks[name]['lines'] = lines.slice(i0+1, i);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
return blocks;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function load(contents, filename='cell') {
|
|
53
|
+
|
|
54
|
+
// Split the file into lines
|
|
55
|
+
let lines = _.split(contents, '\n');
|
|
56
|
+
|
|
57
|
+
// Admissible units
|
|
58
|
+
const units = {
|
|
59
|
+
'LATTICE_CART': ['ang'],
|
|
60
|
+
'POSITIONS_ABS': ['ang']
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
// Find blocks
|
|
64
|
+
let blocks = cellBlocks(lines, units);
|
|
65
|
+
|
|
66
|
+
let pabs = ('POSITIONS_ABS' in blocks);
|
|
67
|
+
let pfrac = ('POSITIONS_FRAC' in blocks);
|
|
68
|
+
let ccart = ('LATTICE_CART' in blocks);
|
|
69
|
+
let cabc = ('LATTICE_ABC' in blocks);
|
|
70
|
+
|
|
71
|
+
switch(pabs+pfrac) {
|
|
72
|
+
case 0:
|
|
73
|
+
throw Error('No positions block found');
|
|
74
|
+
case 2:
|
|
75
|
+
throw Error('Duplicated positions blocks found');
|
|
76
|
+
default:
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
switch(ccart+cabc) {
|
|
81
|
+
case 0:
|
|
82
|
+
throw Error('No lattice block found');
|
|
83
|
+
case 2:
|
|
84
|
+
throw Error('Duplicated lattice blocks found');
|
|
85
|
+
default:
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Parse the cell
|
|
90
|
+
let cell = ccart? blocks['LATTICE_CART'].lines : blocks['LATTICE_ABC'].lines;
|
|
91
|
+
cell = cell.map((l) => (_.trim(l).split(/\s+/).map(parseFloat)));
|
|
92
|
+
|
|
93
|
+
let elems = [];
|
|
94
|
+
let positions = [];
|
|
95
|
+
|
|
96
|
+
let pblock = pabs? blocks['POSITIONS_ABS'].lines : blocks['POSITIONS_FRAC'].lines;
|
|
97
|
+
|
|
98
|
+
pblock.forEach((l) => {
|
|
99
|
+
l = _.trim(l).split(/\s+/);
|
|
100
|
+
if (l.length < 4)
|
|
101
|
+
throw Error('Incomplete line in positions block');
|
|
102
|
+
elems.push(l[0]);
|
|
103
|
+
positions.push(l.slice(1,4).map(parseFloat));
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
var a = new Atoms(elems, positions, cell, {}, pfrac);
|
|
107
|
+
|
|
108
|
+
var structs = {};
|
|
109
|
+
structs[filename] = a;
|
|
110
|
+
|
|
111
|
+
return structs;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export { load };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Function for loading CIF files (wrapper)
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import _ from 'lodash';
|
|
9
|
+
import { Atoms } from 'crystcif-parse';
|
|
10
|
+
|
|
11
|
+
function load(contents, filename) {
|
|
12
|
+
|
|
13
|
+
let structs = Atoms.readCif(contents);
|
|
14
|
+
|
|
15
|
+
if (filename) {
|
|
16
|
+
structs = _.mapKeys(structs, (v, k) => (filename + '_' + k));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return structs;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { load };
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview Function for loading Magres files
|
|
5
|
+
* @module
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import _ from 'lodash';
|
|
9
|
+
import {
|
|
10
|
+
Atoms
|
|
11
|
+
} from 'crystcif-parse';
|
|
12
|
+
import {
|
|
13
|
+
TensorData
|
|
14
|
+
} from '../tensor.js';
|
|
15
|
+
|
|
16
|
+
const MagresUnits = {
|
|
17
|
+
length: {
|
|
18
|
+
ang: 1.0,
|
|
19
|
+
Angstrom: 1.0
|
|
20
|
+
},
|
|
21
|
+
sus: {
|
|
22
|
+
'10^-6.cm^3.mol^-1': 1.0
|
|
23
|
+
},
|
|
24
|
+
ms: {
|
|
25
|
+
ppm: 1.0
|
|
26
|
+
},
|
|
27
|
+
efg: {
|
|
28
|
+
au: 1.0
|
|
29
|
+
},
|
|
30
|
+
isc: {
|
|
31
|
+
'10^19.T^2.J^-1': 1.0
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// Magres parsing utility functions
|
|
36
|
+
function parseNoAtomLine(line, units) {
|
|
37
|
+
// Assumed to be just nine numbers, a full 3x3 matrix.
|
|
38
|
+
// Used for susceptibility
|
|
39
|
+
let tens = [];
|
|
40
|
+
for (let i = 0; i < 3; ++i) {
|
|
41
|
+
tens.push([]);
|
|
42
|
+
for (let j = 0; j < 3; ++j) {
|
|
43
|
+
tens[i].push(parseFloat(line[3 * i + j]) * units);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return new TensorData(tens);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function parseOneAtomLine(line, units, labels) {
|
|
51
|
+
// Species label + index, then nine numbers
|
|
52
|
+
let sp = line[0];
|
|
53
|
+
let sp_i = parseInt(line[1]);
|
|
54
|
+
let i = _.findIndex(labels, function(x) {
|
|
55
|
+
return (x[0] == sp) && (x[1] == sp_i);
|
|
56
|
+
});
|
|
57
|
+
let ltrim = Array.from(line).splice(2);
|
|
58
|
+
|
|
59
|
+
let ans = {
|
|
60
|
+
i: i,
|
|
61
|
+
tens: parseNoAtomLine(ltrim, units)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return ans;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function parseTwoAtomLine(line, units, labels) {
|
|
68
|
+
let sp1 = line[0]
|
|
69
|
+
let sp1_i = parseInt(line[1]);
|
|
70
|
+
let i1 = _.findIndex(labels, function(x) {
|
|
71
|
+
return (x[0] == sp1) && (x[1] == sp1_i);
|
|
72
|
+
});
|
|
73
|
+
let ltrim = Array.from(line).splice(2);
|
|
74
|
+
|
|
75
|
+
let ans = parseOneAtomLine(ltrim, units, labels);
|
|
76
|
+
|
|
77
|
+
ans = {
|
|
78
|
+
i1: i1,
|
|
79
|
+
i2: ans.i,
|
|
80
|
+
tens: ans.tens
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return ans;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const MagresParsers = {
|
|
87
|
+
sus: parseNoAtomLine,
|
|
88
|
+
ms: parseOneAtomLine,
|
|
89
|
+
efg: parseOneAtomLine,
|
|
90
|
+
isc: parseTwoAtomLine
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
function load(contents, filename='magres') {
|
|
94
|
+
|
|
95
|
+
const known_blocks = ['atoms', 'magres'];
|
|
96
|
+
|
|
97
|
+
let lines = _.split(contents, '\n');
|
|
98
|
+
|
|
99
|
+
// First line contains version
|
|
100
|
+
let v_re = /#\$magres-abinitio-v([0-9]+\.[0-9]+)/;
|
|
101
|
+
let v_match = lines[0].match(v_re);
|
|
102
|
+
|
|
103
|
+
if (!v_match) {
|
|
104
|
+
throw Error('Invalid Magres file format: no version line');
|
|
105
|
+
}
|
|
106
|
+
let version = v_match[1];
|
|
107
|
+
|
|
108
|
+
// Start by identifying blocks
|
|
109
|
+
let blocks = {};
|
|
110
|
+
let b_re = /\[(\/)?([a-zA-Z_]+)\]/;
|
|
111
|
+
let b_alt_re = /<(\/)?([a-zA-Z_]+)>/; // Alternative version (old magres tags)
|
|
112
|
+
let mtagtype_detected = false; // Have we found out which type of tags are used?
|
|
113
|
+
let block_name = null;
|
|
114
|
+
let block_lines = [];
|
|
115
|
+
|
|
116
|
+
for (let i = 1; i < lines.length; ++i) {
|
|
117
|
+
|
|
118
|
+
let b_match = lines[i].match(b_re);
|
|
119
|
+
|
|
120
|
+
if (!mtagtype_detected) {
|
|
121
|
+
let b_alt_match = lines[i].match(b_alt_re);
|
|
122
|
+
if (b_alt_match) {
|
|
123
|
+
mtagtype_detected = true;
|
|
124
|
+
b_re = b_alt_re;
|
|
125
|
+
b_match = b_alt_match;
|
|
126
|
+
}
|
|
127
|
+
else if (b_match) {
|
|
128
|
+
mtagtype_detected = true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (b_match) {
|
|
133
|
+
// Start or end?
|
|
134
|
+
if (b_match[1] == '/') {
|
|
135
|
+
if (b_match[2] == block_name) {
|
|
136
|
+
// End block
|
|
137
|
+
blocks[block_name] = block_lines;
|
|
138
|
+
block_name = null;
|
|
139
|
+
block_lines = [];
|
|
140
|
+
} else {
|
|
141
|
+
throw Error('Invalid Magres file format: block closed without opening');
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
if (block_name) {
|
|
145
|
+
throw Error('Invalid Magres file format: block opened without closing');
|
|
146
|
+
}
|
|
147
|
+
block_name = b_match[2];
|
|
148
|
+
}
|
|
149
|
+
} else if (block_name) {
|
|
150
|
+
block_lines.push(lines[i]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Process each block
|
|
155
|
+
for (let bname in blocks) {
|
|
156
|
+
let block = blocks[bname];
|
|
157
|
+
|
|
158
|
+
if (!known_blocks.includes(bname)) {
|
|
159
|
+
// We don't know this block
|
|
160
|
+
blocks[bname] = _.join(block, '\n');
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let data = {};
|
|
165
|
+
|
|
166
|
+
for (let i = 0; i < block.length; ++i) {
|
|
167
|
+
let l = block[i];
|
|
168
|
+
let lspl = _.trim(l).split(/\s+/);
|
|
169
|
+
// Is it a 'units' line?
|
|
170
|
+
if (lspl[0] === 'units') {
|
|
171
|
+
let tag = lspl[1];
|
|
172
|
+
if (tag in data && data[tag].lines.length > 0) {
|
|
173
|
+
// We're being forgiving only of the case where a unit definition is duplicated
|
|
174
|
+
throw Error('Invalid Magres file format: units specified after tag ' + tag + ' has been used');
|
|
175
|
+
}
|
|
176
|
+
data[tag] = {
|
|
177
|
+
'units': lspl[2],
|
|
178
|
+
'lines': []
|
|
179
|
+
};
|
|
180
|
+
} else if (lspl[0] !== '') {
|
|
181
|
+
let tag = lspl[0];
|
|
182
|
+
if (!(tag in data)) {
|
|
183
|
+
data[tag] = {
|
|
184
|
+
'units': null,
|
|
185
|
+
'lines': []
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
data[tag].lines.push(lspl.splice(1));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
blocks[bname] = data;
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Now on to read the blocks themselves
|
|
197
|
+
|
|
198
|
+
let ablock = blocks.atoms;
|
|
199
|
+
|
|
200
|
+
if (!ablock) {
|
|
201
|
+
throw Error('Invalid Magres file format: does not contain atoms block');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Read in the cell, if present
|
|
205
|
+
let cell = null;
|
|
206
|
+
if ('lattice' in ablock) {
|
|
207
|
+
let u = 1.0;
|
|
208
|
+
let uname = ablock.lattice.units;
|
|
209
|
+
if (uname) {
|
|
210
|
+
u = MagresUnits.length[uname];
|
|
211
|
+
if (!u) {
|
|
212
|
+
throw Error('Invalid Magres file format: invalid units for cell');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
cell = [];
|
|
216
|
+
let line = Array.from(ablock.lattice.lines[0]);
|
|
217
|
+
for (let i = 0; i < 3; ++i) {
|
|
218
|
+
cell.push(_.map(line.splice(0, 3), function(x) {
|
|
219
|
+
return parseFloat(x) * u;
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Read in the atom positions and species
|
|
225
|
+
let elems = [];
|
|
226
|
+
let pos = [];
|
|
227
|
+
let mlabels = [];
|
|
228
|
+
let labels = [];
|
|
229
|
+
|
|
230
|
+
if ('atom' in ablock) {
|
|
231
|
+
let u = 1.0;
|
|
232
|
+
let uname = ablock.atom.units;
|
|
233
|
+
if (uname) {
|
|
234
|
+
u = MagresUnits.length[uname];
|
|
235
|
+
if (!u) {
|
|
236
|
+
throw Error('Invalid Magres file format: invalid units for atom');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
for (let i = 0; i < ablock.atom.lines.length; ++i) {
|
|
241
|
+
let l = ablock.atom.lines[i];
|
|
242
|
+
|
|
243
|
+
elems.push(l[0]);
|
|
244
|
+
mlabels.push([l[1], parseInt(l[2])]);
|
|
245
|
+
labels.push(l[1]);
|
|
246
|
+
|
|
247
|
+
pos.push(_.map(l.splice(3), function(x) {
|
|
248
|
+
return parseFloat(x) * u;
|
|
249
|
+
}));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
} else {
|
|
253
|
+
throw Error('Invalid Magres file format: no atom position data found');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Create atoms object
|
|
257
|
+
let atoms = new Atoms(elems, pos, cell, {
|
|
258
|
+
'magres-blocks': blocks,
|
|
259
|
+
'magres-version': version,
|
|
260
|
+
});
|
|
261
|
+
// Add array
|
|
262
|
+
atoms.set_array('labels', labels);
|
|
263
|
+
atoms.set_array('magres-labels', mlabels);
|
|
264
|
+
|
|
265
|
+
let N = elems.length;
|
|
266
|
+
|
|
267
|
+
// Now for the magres stuff
|
|
268
|
+
let mblock = blocks.magres;
|
|
269
|
+
|
|
270
|
+
if (mblock) {
|
|
271
|
+
|
|
272
|
+
for (let tag in mblock) {
|
|
273
|
+
let tag_type = tag.split('_')[0];
|
|
274
|
+
|
|
275
|
+
let u = 1.0;
|
|
276
|
+
let uname = mblock[tag].units;
|
|
277
|
+
if (uname) {
|
|
278
|
+
u = MagresUnits[tag_type][uname];
|
|
279
|
+
if (!u) {
|
|
280
|
+
throw Error('Invalid Magres file format: invalid units for ' + tag);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Initialise as dictionary
|
|
285
|
+
let tag_dimension;
|
|
286
|
+
let tag_data;
|
|
287
|
+
switch (MagresParsers[tag_type]) {
|
|
288
|
+
case parseNoAtomLine:
|
|
289
|
+
tag_dimension = 0;
|
|
290
|
+
break;
|
|
291
|
+
case parseOneAtomLine:
|
|
292
|
+
tag_dimension = 1;
|
|
293
|
+
tag_data = new Array(N);
|
|
294
|
+
break;
|
|
295
|
+
case parseTwoAtomLine:
|
|
296
|
+
tag_dimension = 2;
|
|
297
|
+
tag_data = _.times(N, function() {
|
|
298
|
+
return new Array(N);
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
for (let i = 0; i < mblock[tag].lines.length; ++i) {
|
|
303
|
+
let l = mblock[tag].lines[i];
|
|
304
|
+
let data = MagresParsers[tag_type](l, u, mlabels);
|
|
305
|
+
switch (tag_dimension) {
|
|
306
|
+
case 0:
|
|
307
|
+
tag_data = data;
|
|
308
|
+
break;
|
|
309
|
+
case 1:
|
|
310
|
+
tag_data[data.i] = data.tens;
|
|
311
|
+
break;
|
|
312
|
+
case 2:
|
|
313
|
+
tag_data[data.i1][data.i2] = data.tens;
|
|
314
|
+
tag_data[data.i2][data.i1] = data.tens;
|
|
315
|
+
break;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (tag_dimension == 0) {
|
|
320
|
+
atoms.info[tag] = tag_data;
|
|
321
|
+
} else {
|
|
322
|
+
atoms.set_array(tag, tag_data);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
let structs = {};
|
|
330
|
+
structs[filename] = atoms;
|
|
331
|
+
|
|
332
|
+
return structs;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export {
|
|
336
|
+
load
|
|
337
|
+
};
|