@datagrok/sequence-translator 0.0.6 → 0.0.12
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/css/style.css +18 -0
- package/dist/package-test.js +2387 -0
- package/dist/package.js +5151 -0
- package/jest.config.js +33 -0
- package/package.json +21 -5
- package/setup.cmd +1 -1
- package/src/ICDs.ts +3 -0
- package/src/IDPs.ts +3 -0
- package/src/__jest__/remote.test.ts +49 -0
- package/src/__jest__/test-node.ts +96 -0
- package/src/defineAxolabsPattern.ts +2 -8
- package/src/package-test.ts +2 -1
- package/src/package.ts +186 -703
- package/src/salts.ts +2 -0
- package/src/sources.ts +3 -0
- package/src/structures-works/converters.ts +288 -0
- package/src/structures-works/from-monomers.ts +104 -0
- package/src/{map.ts → structures-works/map.ts} +28 -6
- package/src/structures-works/mol-transformations.ts +432 -0
- package/src/structures-works/save-sense-antisense.ts +51 -0
- package/src/structures-works/sequence-codes-tools.ts +252 -0
- package/src/tests/smiles-tests.ts +1 -1
- package/src/users.ts +3 -0
- package/test-SequenceTranslator-c2bbc2b235db-afc0e1c5.html +245 -0
- package/tsconfig.json +2 -1
- package/src/save-sense-antisense.ts +0 -44
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
import * as OCL from 'openchemlib/full.js';
|
|
2
|
+
|
|
3
|
+
const PHOSHATE = `
|
|
4
|
+
Datagrok monomer library Nucleotides
|
|
5
|
+
|
|
6
|
+
0 0 0 0 0 0 0 V3000
|
|
7
|
+
M V30 BEGIN CTAB
|
|
8
|
+
M V30 COUNTS 5 4 0 0 0
|
|
9
|
+
M V30 BEGIN ATOM
|
|
10
|
+
M V30 1 O -1.5 0 0 0
|
|
11
|
+
M V30 2 P 0 0 0 0
|
|
12
|
+
M V30 3 O 0 1 0 0
|
|
13
|
+
M V30 4 O 0 -1 0 0
|
|
14
|
+
M V30 5 O 1.5 0 0 0
|
|
15
|
+
M V30 END ATOM
|
|
16
|
+
M V30 BEGIN BOND
|
|
17
|
+
M V30 1 1 1 2
|
|
18
|
+
M V30 2 2 2 3
|
|
19
|
+
M V30 3 1 2 4
|
|
20
|
+
M V30 4 1 2 5
|
|
21
|
+
M V30 END BOND
|
|
22
|
+
M V30 END CTAB
|
|
23
|
+
M V30 BEGIN COLLECTION
|
|
24
|
+
M V30 END COLLECTION
|
|
25
|
+
M END`;
|
|
26
|
+
|
|
27
|
+
const THIOPHOSHATE = `
|
|
28
|
+
Datagrok monomer library Nucleotides
|
|
29
|
+
|
|
30
|
+
0 0 0 0 0 0 0 V3000
|
|
31
|
+
M V30 BEGIN CTAB
|
|
32
|
+
M V30 COUNTS 5 4 0 0 0
|
|
33
|
+
M V30 BEGIN ATOM
|
|
34
|
+
M V30 1 O -1.5 0 0 0
|
|
35
|
+
M V30 2 P 0 0 0 0
|
|
36
|
+
M V30 3 O 0 1 0 0
|
|
37
|
+
M V30 4 S 0 -1 0 0
|
|
38
|
+
M V30 5 O 1.5 0 0 0
|
|
39
|
+
M V30 END ATOM
|
|
40
|
+
M V30 BEGIN BOND
|
|
41
|
+
M V30 1 1 1 2
|
|
42
|
+
M V30 2 2 2 3
|
|
43
|
+
M V30 3 1 2 4
|
|
44
|
+
M V30 4 1 2 5
|
|
45
|
+
M V30 END BOND
|
|
46
|
+
M V30 END CTAB
|
|
47
|
+
M V30 BEGIN COLLECTION
|
|
48
|
+
M V30 END COLLECTION
|
|
49
|
+
M END`;
|
|
50
|
+
|
|
51
|
+
const INVABASIC = `
|
|
52
|
+
Datagrok monomer library Nucleotides
|
|
53
|
+
|
|
54
|
+
0 0 0 0 0 0 0 V3000
|
|
55
|
+
M V30 BEGIN CTAB
|
|
56
|
+
M V30 COUNTS 8 8 0 0 0
|
|
57
|
+
M V30 BEGIN ATOM
|
|
58
|
+
M V30 1 O 1.0934 -2.1636 0 0
|
|
59
|
+
M V30 2 C 1.8365 -1.4945 0 0 CFG=2
|
|
60
|
+
M V30 3 C 2.8147 -1.7024 0 0
|
|
61
|
+
M V30 4 C 3.3147 -0.8364 0 0 VAL=3
|
|
62
|
+
M V30 5 O 2.6455 -0.0932 0 0
|
|
63
|
+
M V30 6 C 1.732 -0.5 0 0 CFG=1
|
|
64
|
+
M V30 7 C 0.866 0 0 0
|
|
65
|
+
M V30 8 O 0.866 1 0 0
|
|
66
|
+
M V30 END ATOM
|
|
67
|
+
M V30 BEGIN BOND
|
|
68
|
+
M V30 1 1 2 1 CFG=1
|
|
69
|
+
M V30 2 1 2 3
|
|
70
|
+
M V30 3 1 3 4
|
|
71
|
+
M V30 4 1 4 5
|
|
72
|
+
M V30 5 1 6 5
|
|
73
|
+
M V30 6 1 2 6
|
|
74
|
+
M V30 7 1 6 7 CFG=3
|
|
75
|
+
M V30 8 1 7 8
|
|
76
|
+
M V30 END BOND
|
|
77
|
+
M V30 BEGIN COLLECTION
|
|
78
|
+
M V30 MDLV30/STEABS ATOMS=(2 2 6)
|
|
79
|
+
M V30 END COLLECTION
|
|
80
|
+
M V30 END CTAB
|
|
81
|
+
M END`;
|
|
82
|
+
|
|
83
|
+
export function getNucleotidesMol(smilesCodes: string[], oclRender: boolean = false) {
|
|
84
|
+
const molBlocks: string[] = [];
|
|
85
|
+
|
|
86
|
+
for (let i = 0; i < smilesCodes.length - 1; i++) {
|
|
87
|
+
smilesCodes[i] == 'OP(=O)(O)O' ? molBlocks.push(PHOSHATE) :
|
|
88
|
+
smilesCodes[i] == 'OP(=O)(S)O' ? molBlocks.push(THIOPHOSHATE) :
|
|
89
|
+
smilesCodes[i] == 'O[C@@H]1C[C@@H]O[C@H]1CO' ? molBlocks.push(rotateNucleotidesV3000(INVABASIC)) :
|
|
90
|
+
molBlocks.push(rotateNucleotidesV3000(smilesCodes[i]));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return linkV3000(molBlocks, false, oclRender);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function linkV3000(molBlocks: string[], twoMolecules: boolean = false, oclRender: boolean = false) {
|
|
97
|
+
let macroMolBlock = '\nDatagrok macromolecule handler\n\n';
|
|
98
|
+
macroMolBlock += ' 0 0 0 0 0 0 999 V3000\n';
|
|
99
|
+
macroMolBlock += 'M V30 BEGIN CTAB\n';
|
|
100
|
+
let atomBlock = '';
|
|
101
|
+
let bondBlock = '';
|
|
102
|
+
let collectionBlock = '';
|
|
103
|
+
const collection: number [] = [];
|
|
104
|
+
let natom = 0;
|
|
105
|
+
let nbond = 0;
|
|
106
|
+
let sequenceShift = 0;
|
|
107
|
+
let xShift = 0;
|
|
108
|
+
|
|
109
|
+
if (twoMolecules && molBlocks.length > 1)
|
|
110
|
+
molBlocks[1] = invertNucleotidesV3000(molBlocks[1]);
|
|
111
|
+
|
|
112
|
+
for (let i = 0; i < molBlocks.length; i++) {
|
|
113
|
+
molBlocks[i] = molBlocks[i].replaceAll('(-\nM V30 ', '(')
|
|
114
|
+
.replaceAll('-\nM V30 ', '').replaceAll(' )', ')');
|
|
115
|
+
const numbers = extractAtomsBondsNumbersV3000(molBlocks[i]);
|
|
116
|
+
const coordinates = extractAtomDataV3000(molBlocks[i]);
|
|
117
|
+
let indexAtoms = molBlocks[i].indexOf('M V30 BEGIN ATOM'); // V3000 index for atoms coordinates
|
|
118
|
+
indexAtoms = molBlocks[i].indexOf('\n', indexAtoms);
|
|
119
|
+
let index = indexAtoms;
|
|
120
|
+
let indexEnd = indexAtoms;
|
|
121
|
+
|
|
122
|
+
for (let j = 0; j < numbers.natom; j++) {
|
|
123
|
+
if (coordinates.atomIndex[j] != 1 || i == 0 || twoMolecules) {
|
|
124
|
+
//rewrite atom number
|
|
125
|
+
index = molBlocks[i].indexOf('V30', index) + 4;
|
|
126
|
+
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
127
|
+
const atomNumber = parseInt(molBlocks[i].substring(index, indexEnd)) + natom;
|
|
128
|
+
molBlocks[i] = molBlocks[i].slice(0, index) + atomNumber + molBlocks[i].slice(indexEnd);
|
|
129
|
+
|
|
130
|
+
//rewrite coordinates
|
|
131
|
+
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
132
|
+
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
133
|
+
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
134
|
+
|
|
135
|
+
const totalShift = xShift - coordinates.x[0];
|
|
136
|
+
let coordinate = Math.round(10000*(parseFloat(molBlocks[i].substring(index, indexEnd)) + totalShift))/10000;
|
|
137
|
+
molBlocks[i] = molBlocks[i].slice(0, index) + coordinate + molBlocks[i].slice(indexEnd);
|
|
138
|
+
|
|
139
|
+
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
140
|
+
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
141
|
+
coordinate = Math.round(10000*(parseFloat(molBlocks[i].substring(index, indexEnd)) + sequenceShift))/10000;
|
|
142
|
+
molBlocks[i] = molBlocks[i].slice(0, index) + coordinate + molBlocks[i].slice(indexEnd);
|
|
143
|
+
|
|
144
|
+
index = molBlocks[i].indexOf('\n', index) + 1;
|
|
145
|
+
} else {
|
|
146
|
+
index = molBlocks[i].indexOf('M V30', index) - 1;
|
|
147
|
+
indexEnd = molBlocks[i].indexOf('\n', index + 1);
|
|
148
|
+
molBlocks[i] = molBlocks[i].slice(0, index) + molBlocks[i].slice(indexEnd);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const indexAtomsEnd = molBlocks[i].indexOf('M V30 END ATOM');
|
|
153
|
+
atomBlock += molBlocks[i].substring(indexAtoms + 1, indexAtomsEnd);
|
|
154
|
+
|
|
155
|
+
let indexBonds = molBlocks[i].indexOf('M V30 BEGIN BOND'); // V3000 index for bonds
|
|
156
|
+
indexBonds = molBlocks[i].indexOf('\n', indexBonds);
|
|
157
|
+
index = indexBonds;
|
|
158
|
+
indexEnd = indexBonds;
|
|
159
|
+
|
|
160
|
+
for (let j = 0; j < numbers.nbond; j++) {
|
|
161
|
+
//rewrite bond number
|
|
162
|
+
index = molBlocks[i].indexOf('V30', index) + 4;
|
|
163
|
+
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
164
|
+
const bondNumber = parseInt(molBlocks[i].substring(index, indexEnd)) + nbond;
|
|
165
|
+
molBlocks[i] = molBlocks[i].slice(0, index) + bondNumber + molBlocks[i].slice(indexEnd);
|
|
166
|
+
|
|
167
|
+
//rewrite atom pair in bond
|
|
168
|
+
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
169
|
+
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
170
|
+
indexEnd = molBlocks[i].indexOf(' ', index);
|
|
171
|
+
let atomNumber = parseInt(molBlocks[i].substring(index, indexEnd)) + natom;
|
|
172
|
+
molBlocks[i] = molBlocks[i].slice(0, index) + atomNumber + molBlocks[i].slice(indexEnd);
|
|
173
|
+
index = molBlocks[i].indexOf(' ', index) + 1;
|
|
174
|
+
indexEnd = Math.min(molBlocks[i].indexOf('\n', index), molBlocks[i].indexOf(' ', index));
|
|
175
|
+
atomNumber = parseInt(molBlocks[i].substring(index, indexEnd)) + natom;
|
|
176
|
+
molBlocks[i] = molBlocks[i].slice(0, index) + atomNumber + molBlocks[i].slice(indexEnd);
|
|
177
|
+
|
|
178
|
+
index = molBlocks[i].indexOf('\n', index) + 1;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const indexBondEnd = molBlocks[i].indexOf('M V30 END BOND');
|
|
182
|
+
bondBlock += molBlocks[i].substring(indexBonds + 1, indexBondEnd);
|
|
183
|
+
|
|
184
|
+
let indexCollection = molBlocks[i].indexOf('M V30 MDLV30/STEABS ATOMS=('); // V3000 index for collections
|
|
185
|
+
|
|
186
|
+
while (indexCollection != -1) {
|
|
187
|
+
indexCollection += 28;
|
|
188
|
+
const collectionEnd = molBlocks[i].indexOf(')', indexCollection);
|
|
189
|
+
const collectionEntries = molBlocks[i].substring(indexCollection, collectionEnd).split(' ').slice(1);
|
|
190
|
+
collectionEntries.forEach((e) => {
|
|
191
|
+
collection.push(parseInt(e) + natom);
|
|
192
|
+
});
|
|
193
|
+
indexCollection = collectionEnd;
|
|
194
|
+
indexCollection = molBlocks[i].indexOf('M V30 MDLV30/STEABS ATOMS=(', indexCollection);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
natom += twoMolecules ? numbers.natom : numbers.natom - 1;
|
|
198
|
+
nbond += numbers.nbond;
|
|
199
|
+
xShift += twoMolecules ? 0 : coordinates.x[numbers.natom - 1] - coordinates.x[0];
|
|
200
|
+
sequenceShift += twoMolecules ? -7 : 0;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const entries = 4;
|
|
204
|
+
const collNumber = Math.ceil(collection.length / entries);
|
|
205
|
+
|
|
206
|
+
if (oclRender) {
|
|
207
|
+
collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length;
|
|
208
|
+
|
|
209
|
+
for (let j = 0; j < collection.length; j++)
|
|
210
|
+
collectionBlock += ' ' + collection[j];
|
|
211
|
+
|
|
212
|
+
collectionBlock += ')\n';
|
|
213
|
+
} else {
|
|
214
|
+
collectionBlock += 'M V30 MDLV30/STEABS ATOMS=(' + collection.length + ' -\n';
|
|
215
|
+
for (let i = 0; i < collNumber; i++) {
|
|
216
|
+
collectionBlock += 'M V30 ';
|
|
217
|
+
const entriesCurrent = i + 1 == collNumber ? collection.length - (collNumber - 1)*entries : entries;
|
|
218
|
+
for (let j = 0; j < entriesCurrent; j++) {
|
|
219
|
+
collectionBlock += (j + 1 == entriesCurrent) ?
|
|
220
|
+
(i == collNumber - 1 ? collection[entries*i + j] + ')\n' : collection[entries*i + j] + ' -\n') :
|
|
221
|
+
collection[entries*i + j] + ' ';
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
//generate file
|
|
227
|
+
twoMolecules? natom : natom++;
|
|
228
|
+
macroMolBlock += 'M V30 COUNTS ' + natom + ' ' + nbond + ' 0 0 0\n';
|
|
229
|
+
macroMolBlock += 'M V30 BEGIN ATOM\n';
|
|
230
|
+
macroMolBlock += atomBlock;
|
|
231
|
+
macroMolBlock += 'M V30 END ATOM\n';
|
|
232
|
+
macroMolBlock += 'M V30 BEGIN BOND\n';
|
|
233
|
+
macroMolBlock += bondBlock;
|
|
234
|
+
macroMolBlock += 'M V30 END BOND\n';
|
|
235
|
+
macroMolBlock += 'M V30 BEGIN COLLECTION\n';
|
|
236
|
+
macroMolBlock += collectionBlock;
|
|
237
|
+
macroMolBlock += 'M V30 END COLLECTION\n';
|
|
238
|
+
macroMolBlock += 'M V30 END CTAB\n';
|
|
239
|
+
macroMolBlock += 'M END\n';
|
|
240
|
+
|
|
241
|
+
return macroMolBlock;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function rotateNucleotidesV3000(molecule: string) {
|
|
245
|
+
let molBlock = molecule.includes('M END') ? molecule : OCL.Molecule.fromSmiles(molecule).toMolfileV3();
|
|
246
|
+
const coordinates = extractAtomDataV3000(molBlock);
|
|
247
|
+
const natom = coordinates.atomIndex.length;
|
|
248
|
+
|
|
249
|
+
const indexFivePrime = coordinates.atomIndex.indexOf(1);
|
|
250
|
+
const indexThreePrime = coordinates.atomIndex.indexOf(natom);
|
|
251
|
+
|
|
252
|
+
//fix 5 prime if inadequate
|
|
253
|
+
if (natom > 8)
|
|
254
|
+
fix5Prime(coordinates, indexFivePrime, indexThreePrime);
|
|
255
|
+
|
|
256
|
+
const xCenter = (coordinates.x[indexThreePrime] + coordinates.x[indexFivePrime])/2;
|
|
257
|
+
const yCenter = (coordinates.y[indexThreePrime] + coordinates.y[indexFivePrime])/2;
|
|
258
|
+
|
|
259
|
+
//place to center
|
|
260
|
+
for (let i = 0; i < natom; i++) {
|
|
261
|
+
coordinates.x[i] -= xCenter;
|
|
262
|
+
coordinates.y[i] -= yCenter;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let angle = 0;
|
|
266
|
+
if (coordinates.x[indexFivePrime] == 0)
|
|
267
|
+
angle = coordinates.y[indexFivePrime] > coordinates.y[indexThreePrime] ? Math.PI/2 : 3*Math.PI/2;
|
|
268
|
+
else if (coordinates.y[indexFivePrime] == 0)
|
|
269
|
+
angle = coordinates.x[indexFivePrime] > coordinates.x[indexThreePrime] ? Math.PI : 0;
|
|
270
|
+
else {
|
|
271
|
+
const derivative = coordinates.y[indexFivePrime]/coordinates.x[indexFivePrime];
|
|
272
|
+
angle = derivative > 0 ? Math.PI - Math.atan(derivative) : Math.atan(derivative);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const cos = Math.cos(angle);
|
|
276
|
+
const sin = Math.sin(angle);
|
|
277
|
+
|
|
278
|
+
for (let i = 0; i < natom; i++) {
|
|
279
|
+
const xAdd = coordinates.x[i];
|
|
280
|
+
coordinates.x[i] = xAdd*cos - coordinates.y[i]*sin;
|
|
281
|
+
coordinates.y[i] = xAdd*sin + coordinates.y[i]*cos;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
//place to right
|
|
285
|
+
const xShift = coordinates.x[indexFivePrime];
|
|
286
|
+
for (let i = 0; i < natom; i++)
|
|
287
|
+
coordinates.x[i] -= xShift;
|
|
288
|
+
|
|
289
|
+
//rewrite molBlock
|
|
290
|
+
let index = molBlock.indexOf('M V30 BEGIN ATOM'); // V3000 index for atoms coordinates
|
|
291
|
+
index = molBlock.indexOf('\n', index);
|
|
292
|
+
let indexEnd = index;
|
|
293
|
+
for (let i = 0; i < natom; i++) {
|
|
294
|
+
index = molBlock.indexOf('V30', index) + 4;
|
|
295
|
+
index = molBlock.indexOf(' ', index) + 1;
|
|
296
|
+
index = molBlock.indexOf(' ', index) + 1;
|
|
297
|
+
indexEnd = molBlock.indexOf(' ', index) + 1;
|
|
298
|
+
indexEnd = molBlock.indexOf(' ', indexEnd);
|
|
299
|
+
|
|
300
|
+
molBlock = molBlock.slice(0, index) +
|
|
301
|
+
coordinates.x[i] + ' ' + coordinates.y[i] +
|
|
302
|
+
molBlock.slice(indexEnd);
|
|
303
|
+
|
|
304
|
+
index = molBlock.indexOf('\n', index) + 1;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return molBlock;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function invertNucleotidesV3000(molecule: string) {
|
|
311
|
+
let molBlock = molecule.includes('M END') ? molecule : OCL.Molecule.fromSmiles(molecule).toMolfileV3();
|
|
312
|
+
const coordinates = extractAtomDataV3000(molBlock);
|
|
313
|
+
const natom = coordinates.atomIndex.length;
|
|
314
|
+
|
|
315
|
+
const xCenter = (Math.max(...coordinates.x) + Math.min(...coordinates.x))/2;
|
|
316
|
+
const yCenter = (Math.max(...coordinates.y) + Math.min(...coordinates.y))/2;
|
|
317
|
+
|
|
318
|
+
//place to center
|
|
319
|
+
for (let i = 0; i < natom; i++) {
|
|
320
|
+
coordinates.x[i] -= xCenter;
|
|
321
|
+
coordinates.y[i] -= yCenter;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const angle = Math.PI;
|
|
325
|
+
|
|
326
|
+
const cos = Math.cos(angle);
|
|
327
|
+
const sin = Math.sin(angle);
|
|
328
|
+
|
|
329
|
+
for (let i = 0; i < natom; i++) {
|
|
330
|
+
const xAdd = coordinates.x[i];
|
|
331
|
+
coordinates.x[i] = xAdd*cos - coordinates.y[i]*sin;
|
|
332
|
+
coordinates.y[i] = xAdd*sin + coordinates.y[i]*cos;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
//place back
|
|
336
|
+
const yShift = Math.max(...coordinates.y);
|
|
337
|
+
for (let i = 0; i < natom; i++) {
|
|
338
|
+
coordinates.x[i] += xCenter;
|
|
339
|
+
coordinates.y[i] -= yShift;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
//rewrite molBlock
|
|
343
|
+
let index = molBlock.indexOf('M V30 BEGIN ATOM'); // V3000 index for atoms coordinates
|
|
344
|
+
index = molBlock.indexOf('\n', index);
|
|
345
|
+
let indexEnd = index;
|
|
346
|
+
for (let i = 0; i < natom; i++) {
|
|
347
|
+
index = molBlock.indexOf('V30', index) + 4;
|
|
348
|
+
index = molBlock.indexOf(' ', index) + 1;
|
|
349
|
+
index = molBlock.indexOf(' ', index) + 1;
|
|
350
|
+
indexEnd = molBlock.indexOf(' ', index) + 1;
|
|
351
|
+
indexEnd = molBlock.indexOf(' ', indexEnd);
|
|
352
|
+
|
|
353
|
+
molBlock = molBlock.slice(0, index) +
|
|
354
|
+
coordinates.x[i] + ' ' + coordinates.y[i] +
|
|
355
|
+
molBlock.slice(indexEnd);
|
|
356
|
+
|
|
357
|
+
index = molBlock.indexOf('\n', index) + 1;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return molBlock;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function fix5Prime(coordinates: {atomIndex: number[], atomType: string[], x: number[], y: number[]},
|
|
364
|
+
indexFivePrime: number, indexThreePrime: number) {
|
|
365
|
+
const indexFivePrimeNeighbour = indexFivePrime + 1;
|
|
366
|
+
const xShift = coordinates.x[indexFivePrimeNeighbour];
|
|
367
|
+
const yShift = coordinates.y[indexFivePrimeNeighbour];
|
|
368
|
+
const base3PrimeX = coordinates.x[indexThreePrime] - xShift;
|
|
369
|
+
const base3PrimeY = coordinates.y[indexThreePrime] - yShift;
|
|
370
|
+
const base5PrimeX = coordinates.x[indexFivePrime] - xShift;
|
|
371
|
+
const base5PrimeY = coordinates.y[indexFivePrime] - yShift;
|
|
372
|
+
|
|
373
|
+
const rotated5PrimeX = base5PrimeX*Math.cos(Math.PI*2/3) - base5PrimeY*Math.sin(Math.PI*2/3);
|
|
374
|
+
const rotated5PrimeY = base5PrimeX*Math.sin(Math.PI*2/3) + base5PrimeY*Math.cos(Math.PI*2/3);
|
|
375
|
+
|
|
376
|
+
const dx = base5PrimeX - base3PrimeX;
|
|
377
|
+
const dy = base5PrimeY - base3PrimeY;
|
|
378
|
+
const dxRotated = rotated5PrimeX - base3PrimeX;
|
|
379
|
+
const dyRotated = rotated5PrimeY - base3PrimeY;
|
|
380
|
+
|
|
381
|
+
if (Math.sqrt(dyRotated*dyRotated + dxRotated*dxRotated) >= Math.sqrt(dy*dy + dx*dx)) {
|
|
382
|
+
coordinates.x[indexFivePrime] = rotated5PrimeX + xShift;
|
|
383
|
+
coordinates.y[indexFivePrime] = rotated5PrimeY + yShift;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function extractAtomsBondsNumbersV3000(molBlock: string): {natom: number, nbond: number} {
|
|
388
|
+
molBlock = molBlock.replaceAll('\r', ''); //equalize old and new sdf standards
|
|
389
|
+
let index = molBlock.indexOf('COUNTS') + 7; // V3000 index for atoms and bonds number
|
|
390
|
+
let indexEnd = molBlock.indexOf(' ', index);
|
|
391
|
+
|
|
392
|
+
const atomsNumber = parseInt(molBlock.substring(index, indexEnd));
|
|
393
|
+
index = indexEnd + 1;
|
|
394
|
+
indexEnd = molBlock.indexOf(' ', index);
|
|
395
|
+
const bondsNumber = parseInt(molBlock.substring(index, indexEnd));
|
|
396
|
+
|
|
397
|
+
return {natom: atomsNumber, nbond: bondsNumber};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function extractAtomDataV3000(molBlock: string) {
|
|
401
|
+
const numbers = extractAtomsBondsNumbersV3000(molBlock);
|
|
402
|
+
let index = molBlock.indexOf('M V30 BEGIN ATOM'); // V3000 index for atoms coordinates
|
|
403
|
+
index = molBlock.indexOf('\n', index);
|
|
404
|
+
let indexEnd = index;
|
|
405
|
+
|
|
406
|
+
const indexes: number[] = Array(numbers.natom);
|
|
407
|
+
const types: string[] = Array(numbers.natom);
|
|
408
|
+
const x: number[] = Array(numbers.natom);
|
|
409
|
+
const y: number[] = Array(numbers.natom);
|
|
410
|
+
|
|
411
|
+
for (let i = 0; i < numbers.natom; i++) {
|
|
412
|
+
index = molBlock.indexOf('V30', index) + 4;
|
|
413
|
+
indexEnd = molBlock.indexOf(' ', index);
|
|
414
|
+
indexes[i] = parseInt(molBlock.substring(index, indexEnd));
|
|
415
|
+
|
|
416
|
+
index = indexEnd + 1;
|
|
417
|
+
indexEnd = molBlock.indexOf(' ', index);
|
|
418
|
+
types[i] = molBlock.substring(index, indexEnd);
|
|
419
|
+
|
|
420
|
+
index = indexEnd + 1;
|
|
421
|
+
indexEnd = molBlock.indexOf(' ', index);
|
|
422
|
+
x[i] = parseFloat(molBlock.substring(index, indexEnd));
|
|
423
|
+
|
|
424
|
+
index = indexEnd + 1;
|
|
425
|
+
indexEnd = molBlock.indexOf(' ', index);
|
|
426
|
+
y[i] = parseFloat(molBlock.substring(index, indexEnd));
|
|
427
|
+
|
|
428
|
+
index = molBlock.indexOf('\n', index) + 1;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
return {atomIndex: indexes, atomType: types, x: x, y: y};
|
|
432
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as ui from 'datagrok-api/ui';
|
|
2
|
+
import {sequenceToMolV3000} from '../structures-works/from-monomers';
|
|
3
|
+
import {linkV3000} from '../structures-works/mol-transformations';
|
|
4
|
+
|
|
5
|
+
export function saveSdf(as: string, ss: string, oneEntity: boolean, fit3dx: boolean) {
|
|
6
|
+
const molSS = sequenceToMolV3000(ss);
|
|
7
|
+
const molAS = sequenceToMolV3000(as, true);
|
|
8
|
+
let result: string;
|
|
9
|
+
if (oneEntity)
|
|
10
|
+
result = linkV3000([molSS, molAS], true, !fit3dx) + '\n\n$$$$\n';
|
|
11
|
+
else {
|
|
12
|
+
result =
|
|
13
|
+
molSS + '\n' +
|
|
14
|
+
`> <Sequence>\nSense Strand\n\n$$$$\n` +
|
|
15
|
+
molAS + '\n' +
|
|
16
|
+
`> <Sequence>\nAnti Sense\n\n$$$$\n`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const element = document.createElement('a');
|
|
20
|
+
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
|
|
21
|
+
element.setAttribute('download', ss.replace(/\s/g, '') + '.sdf');
|
|
22
|
+
element.click();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function saveSenseAntiSense() {
|
|
26
|
+
const moleculeSvgDiv = ui.block([]);
|
|
27
|
+
const ssInput = ui.textInput('Sense Strand 5\' ->3\'', '');
|
|
28
|
+
const asInput = ui.textInput('Anti Sense 3\' ->5\'', '');
|
|
29
|
+
const saveOption = ui.switchInput('Save as one entity', true);
|
|
30
|
+
const save3dx = ui.switchInput('Save 3dx', true);
|
|
31
|
+
const saveBtn = ui.button('Save SDF', () =>
|
|
32
|
+
saveSdf(asInput.value, ssInput.value, saveOption.value, save3dx.value));
|
|
33
|
+
|
|
34
|
+
const saveSection = ui.panel([
|
|
35
|
+
ui.div([
|
|
36
|
+
ui.div([
|
|
37
|
+
ui.divH([ui.h1('Inputs')]),
|
|
38
|
+
ui.divV([
|
|
39
|
+
ui.div([ssInput.root]),
|
|
40
|
+
ui.div([asInput.root]),
|
|
41
|
+
saveOption,
|
|
42
|
+
save3dx,
|
|
43
|
+
ui.buttonsInput([saveBtn]),
|
|
44
|
+
], 'ui-form'),
|
|
45
|
+
], 'ui-form'),
|
|
46
|
+
], 'ui-form'),
|
|
47
|
+
moleculeSvgDiv,
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
return saveSection;
|
|
51
|
+
}
|