@datagrok/sequence-translator 1.5.3 → 1.6.1
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 +2 -2
- package/CHANGELOG.md +13 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +2 -2
- package/src/package.ts +1 -0
- package/src/polytool/conversion/pt-chain.ts +38 -635
- package/src/polytool/conversion/pt-conversion.ts +2 -3
- package/src/polytool/conversion/pt-misc.ts +8 -182
- package/src/polytool/conversion/pt-synthetic.ts +282 -0
- package/src/polytool/conversion/pt-tools-helmmol.ts +114 -0
- package/src/polytool/conversion/pt-tools-parse.ts +356 -0
- package/src/polytool/pt-dialog.ts +3 -3
- package/src/polytool/pt-enumerate-seq-dialog.ts +1 -1
- package/src/polytool/pt-enumeration-helm.ts +7 -5
- package/src/polytool/pt-unrule.ts +3 -3
- package/src/tests/polytool-chain-from-notation-tests.ts +34 -33
- package/src/tests/polytool-chain-parse-notation-tests.ts +2 -2
- package/src/tests/polytool-convert-tests.ts +14 -14
- package/src/tests/polytool-detectors-custom-notation-test.ts +1 -1
- package/src/tests/toAtomicLevel-tests.ts +4 -4
- package/src/utils/cyclized.ts +6 -4
|
@@ -1,663 +1,66 @@
|
|
|
1
|
-
import {Atom, IHelmBio, HelmMol, HelmType, JSDraw2ModuleType, OrgType} from '@datagrok-libraries/bio/src/helm/types';
|
|
2
1
|
import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import {Linkage} from './pt-misc';
|
|
3
|
+
import {Rules} from './pt-rules';
|
|
4
|
+
import {HelmMol} from '@datagrok-libraries/bio/src/helm/types';
|
|
5
|
+
import {fromObjectsToHelm, handleDuplicated, handleLinkRules,
|
|
6
|
+
handleReactionRules, parseHelm, parseSeparator} from './pt-tools-parse';
|
|
7
|
+
import {getHelmMol, helmMolToNotation} from './pt-tools-helmmol';
|
|
5
8
|
|
|
6
|
-
import {getOuterIdx, getInnerIdx} from './pt-misc';
|
|
7
|
-
import {Rules, RuleLink, RuleReaction, getMonomerPairs} from './pt-rules';
|
|
8
|
-
|
|
9
|
-
declare const JSDraw2: JSDraw2ModuleType;
|
|
10
|
-
declare const org: OrgType;
|
|
11
|
-
|
|
12
|
-
type Linkage = {
|
|
13
|
-
fChain: number,
|
|
14
|
-
sChain: number,
|
|
15
|
-
/** Continuous 1-based numbering */ fMonomer: number,
|
|
16
|
-
/** Continuous 1-based numbering */ sMonomer: number,
|
|
17
|
-
fR: number,
|
|
18
|
-
sR: number
|
|
19
|
-
}
|
|
20
|
-
export type PtBio = IHelmBio & { i: number, j: number };
|
|
21
|
-
|
|
22
|
-
type PtAtom = Atom<HelmType, PtBio>
|
|
23
9
|
|
|
24
10
|
export class Chain {
|
|
25
11
|
linkages: Linkage[];
|
|
26
12
|
monomers: string[][];
|
|
27
13
|
mol: HelmMol;
|
|
28
14
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
15
|
+
underRules: boolean = false;
|
|
16
|
+
linkagesUnderRules: Linkage[];
|
|
17
|
+
monomersUnderRules: string[][];
|
|
18
|
+
molUnderRules: HelmMol;
|
|
19
|
+
|
|
20
|
+
constructor(monomers: string[][], linkages: Linkage[], protected helmHelper: IHelmHelper) {
|
|
33
21
|
this.linkages = linkages;
|
|
34
22
|
this.monomers = monomers;
|
|
35
|
-
this.mol =
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Parse harmonized sequence (template) from pseudo helm */
|
|
39
|
-
static parseHelm(helm: string, helmHelper: IHelmHelper) {
|
|
40
|
-
const ea = /(\w+\{.*\})\$(.*)\$(.*)\$(.*)\$/g.exec(helm)!;
|
|
41
|
-
// const fragmentation = helm.split('$');
|
|
42
|
-
const fragmentation = [ea[1], ea[2], ea[3], ea[4]];
|
|
43
|
-
|
|
44
|
-
const rawFragments = fragmentation[0].split('|');
|
|
45
|
-
const rawLinkages = fragmentation[1].split('|');
|
|
46
|
-
|
|
47
|
-
const monomers = new Array<Array<string>>(rawFragments.length);
|
|
48
|
-
const linkages: Linkage[] = [];
|
|
49
|
-
|
|
50
|
-
const resHwe = helmHelper.createHelmWebEditor();
|
|
51
|
-
const resMol = resHwe.editor.m;
|
|
52
|
-
|
|
53
|
-
let counter = 0;
|
|
54
|
-
const p = new JSDraw2.Point(0, 0);
|
|
55
|
-
//HELM parsing
|
|
56
|
-
for (let i = 0; i < rawFragments.length; i++) {
|
|
57
|
-
const idxStart = rawFragments[i].indexOf('{');
|
|
58
|
-
const idxEnd = rawFragments[i].indexOf('}');
|
|
59
|
-
|
|
60
|
-
monomers[i] = rawFragments[i].slice(idxStart + 1, idxEnd).split('.').map((s) => cleanupHelmSymbol(s));
|
|
61
|
-
for (let j = 0; j < monomers[i].length; j++) {
|
|
62
|
-
const elem = monomers[i][j];
|
|
63
|
-
const bio: PtBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
|
|
64
|
-
const atom = new JSDraw2.Atom<HelmType, IHelmBio>(p, elem, bio);
|
|
65
|
-
resMol.addAtom(atom);
|
|
66
|
-
|
|
67
|
-
if (j !== 0) {
|
|
68
|
-
const atom1 = resMol.atoms[counter - 1];
|
|
69
|
-
const atom2 = resMol.atoms[counter];
|
|
70
|
-
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
71
|
-
bond.r1 = 2;
|
|
72
|
-
bond.r2 = 1;
|
|
73
|
-
resMol.addBond(bond);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
counter++;
|
|
77
|
-
p.x += JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
|
|
78
|
-
}
|
|
79
|
-
p.y += 4 * JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
//HELM parsing
|
|
83
|
-
for (let i = 0; i < rawLinkages.length; i++) {
|
|
84
|
-
if (rawLinkages[i] !== '' && rawLinkages[i] !== 'V2.0') {
|
|
85
|
-
const rawData = rawLinkages[i].split(',');
|
|
86
|
-
const fChainIdx = parseInt(rawData[0].replace('PEPTIDE', '')) - 1;
|
|
87
|
-
const sChainIdx = parseInt(rawData[1].replace('PEPTIDE', '')) - 1;
|
|
88
|
-
const rawDataConnections = rawData[2].split('-');
|
|
89
|
-
const rawDataConnection1 = rawDataConnections[0].split(':');
|
|
90
|
-
const rawDataConnection2 = rawDataConnections[1].split(':');
|
|
91
|
-
|
|
92
|
-
linkages.push({
|
|
93
|
-
fChain: fChainIdx,
|
|
94
|
-
sChain: sChainIdx,
|
|
95
|
-
fMonomer: getOuterIdx(parseInt(rawDataConnection1[0]), fChainIdx, monomers),
|
|
96
|
-
sMonomer: getOuterIdx(parseInt(rawDataConnection2[0]), sChainIdx, monomers),
|
|
97
|
-
fR: parseInt(rawDataConnection1[1].replace('R', '')),
|
|
98
|
-
sR: parseInt(rawDataConnection2[1].replace('R', '')),
|
|
99
|
-
});
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
for (let i = 0; i < linkages.length; i++) {
|
|
104
|
-
const atom1 = resMol.atoms[linkages[i].fMonomer - 1];
|
|
105
|
-
const atom2 = resMol.atoms[linkages[i].sMonomer - 1];
|
|
106
|
-
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
107
|
-
bond.r1 = linkages[i].fR;
|
|
108
|
-
bond.r2 = linkages[i].sR;
|
|
109
|
-
resMol.addBond(bond);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return new Chain(monomers, linkages, resMol, helmHelper);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/** Get macromolecule from harmonized sequence (template) */
|
|
116
|
-
applyRules(rules: Rules): Chain {
|
|
117
|
-
const newNotation = this.getNotation();
|
|
118
|
-
return Chain.fromNotation(newNotation, rules, this.helmHelper);
|
|
23
|
+
this.mol = getHelmMol(linkages, monomers, helmHelper);
|
|
119
24
|
}
|
|
120
25
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
const mainFragments: string[] = [];
|
|
126
|
-
const linkages: Linkage[] = [];
|
|
127
|
-
|
|
128
|
-
//NOTICE: this works only with simple single heterodimers
|
|
129
|
-
const heterodimeric = heterodimerCode !== null ? sequence.split(`(${rules.heterodimerCode!})`) : '';
|
|
130
|
-
if (heterodimerCode !== null && heterodimeric.length > 1) {
|
|
131
|
-
linkages.push({fChain: 0, sChain: 1, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
|
|
132
|
-
mainFragments.push(heterodimeric[1].replaceAll('{', '').replaceAll('}', ''));
|
|
133
|
-
mainFragments.push(heterodimeric[2].replaceAll('{', '').replaceAll('}', ''));
|
|
134
|
-
} else {
|
|
135
|
-
mainFragments.push(sequence);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
//NOTICE: this works only with simple single dimers
|
|
139
|
-
for (let i = 0; i < mainFragments.length; i++) {
|
|
140
|
-
if (homodimerCode !== null && mainFragments[i].includes(`(${homodimerCode!})`)) {
|
|
141
|
-
const idxSequence = mainFragments.length;
|
|
142
|
-
|
|
143
|
-
linkages.push({fChain: i, sChain: idxSequence, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
|
|
144
|
-
const rawDimer = mainFragments[i].replace(`(${homodimerCode!})`, '');
|
|
145
|
-
const idx = rawDimer.indexOf('{');
|
|
146
|
-
const linker = rawDimer.slice(0, idx);
|
|
147
|
-
const body = rawDimer.replace(linker, '').replaceAll('{', '').replaceAll('}', '');
|
|
148
|
-
|
|
149
|
-
mainFragments[i] = linker + body;
|
|
150
|
-
mainFragments.push(body);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
for (let i = 0; i < mainFragments.length; i++) {
|
|
155
|
-
if (homodimerCode !== null && mainFragments[i].includes(`(${homodimerCode!})`)) {
|
|
156
|
-
const idxSequence = mainFragments.length;
|
|
157
|
-
|
|
158
|
-
linkages.push({fChain: i, sChain: idxSequence, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
|
|
159
|
-
const rawDimer = mainFragments[i].replace(`(${homodimerCode!})`, '');
|
|
160
|
-
const idx = rawDimer.indexOf('{');
|
|
161
|
-
const linker = rawDimer.slice(0, idx);
|
|
162
|
-
const body = rawDimer.replace(linker, '').replaceAll('{', '').replaceAll('}', '');
|
|
163
|
-
|
|
164
|
-
mainFragments[i] = linker + body;
|
|
165
|
-
mainFragments.push(body);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const monomers = new Array<Array<string>>(mainFragments.length);
|
|
170
|
-
|
|
171
|
-
for (let i = 0; i < mainFragments.length; i++) {
|
|
172
|
-
const rawMonomers = mainFragments[i].split('-');
|
|
173
|
-
const linkedPositions = this.getLinkedPositions(rawMonomers, rules.linkRules);
|
|
174
|
-
const [monomersCycled, allPos1, allPos2, allAttaches1, allAttaches2] =
|
|
175
|
-
this.getAllCycles(rules.linkRules, rawMonomers, linkedPositions);
|
|
176
|
-
|
|
177
|
-
const monomersReady = new Array<string>(monomersCycled.length);
|
|
178
|
-
// for (let j = 0; j < monomersCycled.length; j++)
|
|
179
|
-
// monomersReady[j] = `[${monomersCycled[j]}]`;
|
|
180
|
-
|
|
181
|
-
for (let j = 0; j < allPos1.length; j++) {
|
|
182
|
-
linkages.push({
|
|
183
|
-
fChain: i,
|
|
184
|
-
sChain: i,
|
|
185
|
-
fMonomer: allPos1[j],
|
|
186
|
-
sMonomer: allPos2[j],
|
|
187
|
-
fR: allAttaches1[j],
|
|
188
|
-
sR: allAttaches2[j],
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
monomers[i] = monomersCycled;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const monomersAll: string[][] = [];
|
|
196
|
-
|
|
197
|
-
const resHwe = helmHelper.createHelmWebEditor();
|
|
198
|
-
const resMol = resHwe.editor.m;
|
|
199
|
-
|
|
200
|
-
let counter = 0;
|
|
201
|
-
const p = new JSDraw2.Point(0, 0);
|
|
202
|
-
for (let i = 0; i < monomers.length; i++) {
|
|
203
|
-
const linkedPositions = this.getLinkedPositions(monomers[i], rules.reactionRules);
|
|
204
|
-
const [monomersCycled, allPos1, allPos2, ruleN] =
|
|
205
|
-
this.getAllReactants(rules.reactionRules, monomers[i], linkedPositions);
|
|
206
|
-
|
|
207
|
-
if (allPos1.length >= 1) {
|
|
208
|
-
const ch1 = new Array<string>(allPos2[0] - 1);
|
|
209
|
-
const ch2 = new Array<string>(monomersCycled.length - allPos2[0]);
|
|
210
|
-
for (let j = 0; j < allPos2[0] - 1; j++) {
|
|
211
|
-
const elem = ch1[j] = monomersCycled[j];
|
|
212
|
-
const bio: PtBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
|
|
213
|
-
const atom: PtAtom = new JSDraw2.Atom<HelmType, PtBio>(p, elem, bio);
|
|
214
|
-
resMol.addAtom(atom);
|
|
215
|
-
|
|
216
|
-
if (j > 0) {
|
|
217
|
-
const atom1 = resMol.atoms[counter - 1];
|
|
218
|
-
const atom2 = resMol.atoms[counter];
|
|
219
|
-
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
220
|
-
bond.r1 = 2;
|
|
221
|
-
bond.r2 = 1;
|
|
222
|
-
resMol.addBond(bond);
|
|
223
|
-
}
|
|
224
|
-
counter++;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
for (let j = allPos2[0]; j < monomersCycled.length; j++) {
|
|
228
|
-
const elem = ch2[j - allPos2[0]] = monomersCycled[j];
|
|
229
|
-
const bio: PtBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
|
|
230
|
-
const atom: PtAtom = new JSDraw2.Atom<HelmType, PtBio>(p, elem, bio);
|
|
231
|
-
resMol.addAtom(atom);
|
|
232
|
-
|
|
233
|
-
if (j > allPos2[0]) {
|
|
234
|
-
const atom1 = resMol.atoms[counter - 1];
|
|
235
|
-
const atom2 = resMol.atoms[counter];
|
|
236
|
-
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
237
|
-
bond.r1 = 2;
|
|
238
|
-
bond.r2 = 1;
|
|
239
|
-
resMol.addBond(bond);
|
|
240
|
-
}
|
|
241
|
-
counter++;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
resMol.atoms[allPos1[0] - 1].elem = ch1[allPos1[0] - 1] = rules.reactionRules[ruleN[0]].name;
|
|
245
|
-
|
|
246
|
-
for (let j = 0; j < linkages.length; j++) {
|
|
247
|
-
if (linkages[j].fMonomer > allPos2[0]) {
|
|
248
|
-
linkages[j].fMonomer -= allPos2[0];
|
|
249
|
-
linkages[j].fChain++;
|
|
250
|
-
}
|
|
251
|
-
if (linkages[j].sMonomer > allPos2[0]) {
|
|
252
|
-
linkages[j].sMonomer -= allPos2[0];
|
|
253
|
-
linkages[j].sChain++;
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
linkages.push({
|
|
257
|
-
fChain: 0,
|
|
258
|
-
sChain: 0,
|
|
259
|
-
fMonomer: allPos1[0],
|
|
260
|
-
sMonomer: allPos2[0] - 1,
|
|
261
|
-
fR: 3,
|
|
262
|
-
sR: 2,
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
linkages.push({
|
|
266
|
-
fChain: 0,
|
|
267
|
-
sChain: 1,
|
|
268
|
-
fMonomer: allPos1[0],
|
|
269
|
-
sMonomer: 1,
|
|
270
|
-
fR: 4,
|
|
271
|
-
sR: 1,
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
const monomersReady1 = new Array<string>(ch1.length);
|
|
275
|
-
for (let j = 0; j < ch1.length; j++)
|
|
276
|
-
monomersReady1[j] = `[${ch1[j]}]`;
|
|
277
|
-
const monomersReady2 = new Array<string>(ch2.length);
|
|
278
|
-
for (let j = 0; j < ch2.length; j++)
|
|
279
|
-
monomersReady2[j] = `[${ch2[j]}]`;
|
|
280
|
-
|
|
281
|
-
monomersAll.push(ch1);
|
|
282
|
-
monomersAll.push(ch2);
|
|
283
|
-
} else {
|
|
284
|
-
for (let j = 0; j < monomers[i].length; j++) {
|
|
285
|
-
const elem = monomers[i][j];
|
|
286
|
-
const bio: PtBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
|
|
287
|
-
const atom: PtAtom = new JSDraw2.Atom<HelmType, PtBio>(p, elem, bio);
|
|
288
|
-
resMol.addAtom(atom);
|
|
289
|
-
|
|
290
|
-
if (j > 0) {
|
|
291
|
-
const atom1 = resMol.atoms[counter - 1];
|
|
292
|
-
const atom2 = resMol.atoms[counter];
|
|
293
|
-
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
294
|
-
bond.r1 = 2;
|
|
295
|
-
bond.r2 = 1;
|
|
296
|
-
resMol.addBond(bond);
|
|
297
|
-
}
|
|
298
|
-
counter++;
|
|
299
|
-
}
|
|
300
|
-
monomersAll.push(monomers[i]);
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
for (const l of linkages) {
|
|
305
|
-
const atom1 = resMol.atoms[l.fMonomer - 1];
|
|
306
|
-
const atom2 = resMol.atoms[l.sMonomer - 1];
|
|
307
|
-
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
308
|
-
bond.r1 = l.fR;
|
|
309
|
-
bond.r2 = l.sR;
|
|
310
|
-
resMol.addBond(bond);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const chain = new Chain(monomersAll, linkages, resMol, helmHelper);
|
|
26
|
+
/** Parse from separator or sequence notation (template) */
|
|
27
|
+
static fromSeparator(sequence: string, helmHelper: IHelmHelper): Chain {
|
|
28
|
+
const [linkages, mainFragments] = parseSeparator(sequence);
|
|
29
|
+
const chain = new Chain(mainFragments, linkages, helmHelper);
|
|
314
30
|
return chain;
|
|
315
31
|
}
|
|
316
32
|
|
|
317
|
-
/** Parse harmonized sequence
|
|
318
|
-
static
|
|
319
|
-
const mainFragments
|
|
320
|
-
|
|
321
|
-
const linkages: Linkage[] = [];
|
|
322
|
-
|
|
323
|
-
const resHwe = helmHelper.createHelmWebEditor();
|
|
324
|
-
const resMol = resHwe.editor.m;
|
|
325
|
-
|
|
326
|
-
const rxp = /(\(.\d+\))?\{[^\}]*\}/g;
|
|
327
|
-
const seqs: string [] = [];
|
|
328
|
-
seqs.push(sequence.replaceAll(rxp, ''));
|
|
329
|
-
|
|
330
|
-
//const l = (rxpRes?.length) ?? -1;
|
|
331
|
-
|
|
332
|
-
const matches = sequence.matchAll(rxp);
|
|
333
|
-
//const rxpRes = rxp.exec(sequence);
|
|
334
|
-
for (const m of matches) {
|
|
335
|
-
const str = m![0];
|
|
336
|
-
if (str)
|
|
337
|
-
seqs.push(str);
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
let counter = 0;
|
|
341
|
-
for (let i = 0; i < seqs.length; i++) {
|
|
342
|
-
const splMonomers = seqs[i].split('-');
|
|
343
|
-
const monomers: string [] = new Array<string>(splMonomers.length);
|
|
344
|
-
let spmCount: number = 0;
|
|
345
|
-
for (let j = 0; j < splMonomers.length; j++) {
|
|
346
|
-
const monomer = splMonomers[j].replace('{', '').replace('}', '');
|
|
347
|
-
if (monomer !== '') {
|
|
348
|
-
monomers[j] = monomer;
|
|
349
|
-
counter++;
|
|
350
|
-
spmCount++;
|
|
351
|
-
} else {
|
|
352
|
-
linkages.push({fChain: i, sChain: i + 1, fMonomer: counter, sMonomer: counter + 1, fR: 1, sR: 1});
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
mainFragments.push(monomers.slice(0, spmCount));
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
counter = 0;
|
|
359
|
-
const p = new JSDraw2.Point(0, 0);
|
|
360
|
-
for (let i = 0; i < mainFragments.length; i++) {
|
|
361
|
-
for (let j = 0; j < mainFragments[i].length; j++) {
|
|
362
|
-
if (!!mainFragments[i][j]) {
|
|
363
|
-
const elem = mainFragments[i][j];
|
|
364
|
-
const bio: PtBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
|
|
365
|
-
const atom = new JSDraw2.Atom<HelmType, IHelmBio>(p, elem, bio);
|
|
366
|
-
resMol.addAtom(atom);
|
|
367
|
-
|
|
368
|
-
if (j !== 0) {
|
|
369
|
-
const atom1 = resMol.atoms[counter - 1];
|
|
370
|
-
const atom2 = resMol.atoms[counter];
|
|
371
|
-
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
372
|
-
bond.r1 = 2;
|
|
373
|
-
bond.r2 = 1;
|
|
374
|
-
resMol.addBond(bond);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
counter++;
|
|
378
|
-
p.x += JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
|
|
379
|
-
}
|
|
380
|
-
p.y += 4 * JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
for (let i = 0; i < linkages.length; i++) {
|
|
385
|
-
const atom1 = resMol.atoms[linkages[i].fMonomer - 1];
|
|
386
|
-
const atom2 = resMol.atoms[linkages[i].sMonomer - 1];
|
|
387
|
-
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
388
|
-
bond.r1 = linkages[i].fR;
|
|
389
|
-
bond.r2 = linkages[i].sR;
|
|
390
|
-
resMol.addBond(bond);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const chain = new Chain(mainFragments, linkages, resMol, helmHelper);
|
|
33
|
+
/** Parse harmonized sequence (template) from pseudo helm */
|
|
34
|
+
static fromHelm(sequence: string, helmHelper: IHelmHelper) : Chain {
|
|
35
|
+
const [linkages, mainFragments] = parseHelm(sequence);
|
|
36
|
+
const chain = new Chain(mainFragments, linkages, helmHelper);
|
|
394
37
|
return chain;
|
|
395
38
|
}
|
|
396
39
|
|
|
397
|
-
getHelmChanged(changeNumber: number, monomer: string): string {
|
|
398
|
-
//TODO: make more efficient
|
|
399
|
-
let counter = 0;
|
|
400
|
-
let idx1 = 0;
|
|
401
|
-
let idx2 = 0;
|
|
402
|
-
loop1:
|
|
403
|
-
for (let i = 0; i < this.monomers.length; i++) {
|
|
404
|
-
loop2:
|
|
405
|
-
for (let j = 0; j < this.monomers[i].length; j++) {
|
|
406
|
-
if (counter == changeNumber) {
|
|
407
|
-
idx1 = i;
|
|
408
|
-
idx2 = j;
|
|
409
|
-
break loop1;
|
|
410
|
-
}
|
|
411
|
-
counter++;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
const previous = this.monomers[idx1][idx2];
|
|
416
|
-
|
|
417
|
-
this.monomers[idx1][idx2] = `[${monomer}]`;
|
|
418
|
-
const res = this.getHelm();
|
|
419
|
-
this.monomers[idx1][idx2] = previous;
|
|
420
|
-
|
|
421
|
-
return res;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/** Gets harmonized sequence (template) pseudo helm */
|
|
425
|
-
getNotationHelm(): string {
|
|
426
|
-
return this.getHelm();
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/** Gets harmonized sequence (template) pseudo helm */
|
|
430
|
-
getHelm(): string {
|
|
431
|
-
let helm = '';
|
|
432
|
-
for (let i = 0; i < this.monomers.length; i++) {
|
|
433
|
-
if (i > 0)
|
|
434
|
-
helm += '|';
|
|
435
|
-
|
|
436
|
-
helm += `PEPTIDE${i + 1}{`;
|
|
437
|
-
|
|
438
|
-
for (let j = 0; j < this.monomers[i].length; j++) {
|
|
439
|
-
if (j > 0)
|
|
440
|
-
helm += '.';
|
|
441
|
-
const symbol = this.monomers[i][j];
|
|
442
|
-
helm += symbol.length > 1 ? `[${symbol}]` : symbol;
|
|
443
|
-
}
|
|
444
|
-
helm += `}`;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
helm += '$';
|
|
448
|
-
|
|
449
|
-
for (let i = 0; i < this.linkages.length; i++) {
|
|
450
|
-
if (i > 0)
|
|
451
|
-
helm += '|';
|
|
452
|
-
helm += `PEPTIDE${this.linkages[i].fChain + 1},PEPTIDE${this.linkages[i].sChain + 1},`;
|
|
453
|
-
|
|
454
|
-
helm += `${getInnerIdx(this.linkages[i].fMonomer - 1, this.monomers)[0] + 1}:R${this.linkages[i].fR}-`;
|
|
455
|
-
helm += `${getInnerIdx(this.linkages[i].sMonomer - 1, this.monomers)[0] + 1}:R${this.linkages[i].sR}`;
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
helm += '$$$' + 'V2.0';
|
|
459
|
-
return helm;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
40
|
getNotation(): string {
|
|
463
|
-
|
|
464
|
-
const bonds = this.mol.bonds;
|
|
465
|
-
const chains: number[] = [];
|
|
466
|
-
const specialBonds: number[] = [];
|
|
467
|
-
for (let i = 0; i < bonds.length!; i++) {
|
|
468
|
-
//@ts-ignore
|
|
469
|
-
if (bonds[i].a1.bio.i !== bonds[i].a2.bio.i)
|
|
470
|
-
specialBonds.push(i);
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
for (let i = 0; i < atoms.length!; i++) {
|
|
474
|
-
//@ts-ignore
|
|
475
|
-
const atomChain = atoms[i].bio?.i;
|
|
476
|
-
if (atomChain + 1 > chains.length)
|
|
477
|
-
chains.push(1);
|
|
478
|
-
else
|
|
479
|
-
chains[atomChain]++;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
const simpleChains: string[][] = new Array(chains.length);
|
|
483
|
-
let counter = 0;
|
|
484
|
-
for (let i = 0; i < chains.length!; i++) {
|
|
485
|
-
const simpleChain: string[] = new Array(chains[i]);
|
|
486
|
-
for (let j = 0; j < chains[i]; j++) {
|
|
487
|
-
simpleChain[j] = atoms[counter].elem;
|
|
488
|
-
counter++;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
simpleChains[i] = simpleChain;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
let res = '';
|
|
495
|
-
for (let i = 0; i < simpleChains.length; i++) {
|
|
496
|
-
let chainAdd = '';
|
|
497
|
-
|
|
498
|
-
for (let j = 0; j < simpleChains[i].length; j++)
|
|
499
|
-
chainAdd += `${j == 0 ? '' : '-'}${simpleChains[i][j]}`;
|
|
500
|
-
|
|
501
|
-
if (i !== 0) {
|
|
502
|
-
const rxp = /(\(.\d+\))/;
|
|
503
|
-
const match = chainAdd.match(rxp);
|
|
504
|
-
chainAdd = chainAdd.replace(match?.[0]!, '');
|
|
505
|
-
const group = match ? match?.[0]! : '';
|
|
506
|
-
chainAdd = `${group}{${chainAdd}}`;
|
|
507
|
-
} else {
|
|
508
|
-
if (simpleChains.length > 1) {
|
|
509
|
-
//@ts-ignore
|
|
510
|
-
const firstAtomLinks = bonds[specialBonds[0]].a1.bio.i == 0 && bonds[specialBonds[0]].a1.bio.j == 0;
|
|
511
|
-
//@ts-ignore
|
|
512
|
-
const secondAtomLinks = bonds[specialBonds[0]].a2.bio.i == 1 && bonds[specialBonds[0]].a1.bio.j == 0;
|
|
513
|
-
if (firstAtomLinks && secondAtomLinks)
|
|
514
|
-
chainAdd += '-';
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
res += chainAdd;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
return res;
|
|
41
|
+
return helmMolToNotation(this.mol);
|
|
522
42
|
}
|
|
523
43
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
let firstFound = false;
|
|
530
|
-
let secondFound = false;
|
|
531
|
-
let firstIsFirst = false;
|
|
532
|
-
let firstEntryIndex = -1;
|
|
533
|
-
let secondEntryIndex = -1;
|
|
534
|
-
const add = `(${rules[i].code})`;
|
|
535
|
-
|
|
536
|
-
const [firstMonomers, secondMonomers] = getMonomerPairs(rules[i]);
|
|
537
|
-
|
|
538
|
-
if (firstMonomers.length > 0) {
|
|
539
|
-
for (let j = 0; j < firstMonomers.length; j++) {
|
|
540
|
-
for (let k = 0; k < monomers.length; k++) {
|
|
541
|
-
if (monomers[k].includes(add)) {
|
|
542
|
-
if (firstFound) {
|
|
543
|
-
if (firstIsFirst && monomers[k] == secondMonomers[j] + add) {
|
|
544
|
-
secondFound = true;
|
|
545
|
-
secondEntryIndex = k;
|
|
546
|
-
break;
|
|
547
|
-
} else if (!firstIsFirst && monomers[k] == firstMonomers[j] + add) {
|
|
548
|
-
secondFound = true;
|
|
549
|
-
secondEntryIndex = k;
|
|
550
|
-
break;
|
|
551
|
-
} else {
|
|
552
|
-
continue;
|
|
553
|
-
}
|
|
554
|
-
} else {
|
|
555
|
-
if (monomers[k] == firstMonomers[j] + add) {
|
|
556
|
-
firstFound = true;
|
|
557
|
-
firstIsFirst = true;
|
|
558
|
-
firstEntryIndex = k;
|
|
559
|
-
} else if (monomers[k] == secondMonomers[j] + add) {
|
|
560
|
-
firstFound = true;
|
|
561
|
-
firstIsFirst = false;
|
|
562
|
-
firstEntryIndex = k;
|
|
563
|
-
} else {
|
|
564
|
-
continue;
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
if (!(firstFound && secondFound))
|
|
571
|
-
continue;
|
|
572
|
-
else if (firstIsFirst)
|
|
573
|
-
result.push([firstEntryIndex, secondEntryIndex, i]);
|
|
574
|
-
else
|
|
575
|
-
result.push([secondEntryIndex, firstEntryIndex, i]);
|
|
576
|
-
}
|
|
577
|
-
} else {
|
|
578
|
-
for (let k = 0; k < monomers.length; k++) {
|
|
579
|
-
if (monomers[k].includes(add)) {
|
|
580
|
-
if (firstFound) {
|
|
581
|
-
if (firstIsFirst && monomers[k]) {
|
|
582
|
-
secondFound = true;
|
|
583
|
-
secondEntryIndex = k;
|
|
584
|
-
break;
|
|
585
|
-
} else if (!firstIsFirst && monomers[k]) {
|
|
586
|
-
secondFound = true;
|
|
587
|
-
secondEntryIndex = k;
|
|
588
|
-
break;
|
|
589
|
-
} else {
|
|
590
|
-
continue;
|
|
591
|
-
}
|
|
592
|
-
} else {
|
|
593
|
-
firstFound = true;
|
|
594
|
-
firstIsFirst = true;
|
|
595
|
-
firstEntryIndex = k;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
if (!(firstFound && secondFound))
|
|
601
|
-
continue;
|
|
602
|
-
else if (firstIsFirst)
|
|
603
|
-
result.push([firstEntryIndex, secondEntryIndex, i]);
|
|
604
|
-
else
|
|
605
|
-
result.push([secondEntryIndex, firstEntryIndex, i]);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
return result;
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
protected static getAllCycles(rules: RuleLink[], monomers: string [], positions: [number, number, number][]):
|
|
613
|
-
[string [], number [], number [], number [], number []] {
|
|
614
|
-
const allPos1: number [] = [];
|
|
615
|
-
const allPos2: number [] = [];
|
|
616
|
-
const allAttaches1: number [] = [];
|
|
617
|
-
const allAttaches2: number [] = [];
|
|
618
|
-
const count = positions.length;
|
|
619
|
-
|
|
620
|
-
for (let i = 0; i < count; i++) {
|
|
621
|
-
if (positions[i][0] == -1)
|
|
622
|
-
continue;
|
|
623
|
-
|
|
624
|
-
const ruleNum = positions [i][2];
|
|
625
|
-
const code = rules[ruleNum].code;
|
|
626
|
-
|
|
627
|
-
monomers[positions[i][0]] = monomers[positions[i][0]].replace(`(${code})`, '');
|
|
628
|
-
monomers[positions[i][1]] = monomers[positions[i][1]].replace(`(${code})`, '');
|
|
629
|
-
|
|
630
|
-
allPos1.push(positions[i][0] + 1);
|
|
631
|
-
allPos2.push(positions[i][1] + 1);
|
|
632
|
-
allAttaches1.push(rules[ruleNum].firstLinkingGroup);
|
|
633
|
-
allAttaches2.push(rules[ruleNum].secondLinkingGroup);
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
return [monomers, allPos1, allPos2, allAttaches1, allAttaches2];
|
|
44
|
+
getHelm(): string {
|
|
45
|
+
if (this.underRules)
|
|
46
|
+
return fromObjectsToHelm(this.linkagesUnderRules, this.monomersUnderRules);
|
|
47
|
+
else
|
|
48
|
+
return fromObjectsToHelm(this.linkages, this.monomers);
|
|
637
49
|
}
|
|
638
50
|
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
const
|
|
642
|
-
const allPos2: number [] = [];
|
|
643
|
-
const rule: number [] = [];
|
|
644
|
-
const count = positions.length;
|
|
645
|
-
|
|
646
|
-
for (let i = 0; i < count; i++) {
|
|
647
|
-
if (positions[i][0] == -1)
|
|
648
|
-
continue;
|
|
649
|
-
|
|
650
|
-
const ruleNum = positions [i][2];
|
|
651
|
-
const code = rules[ruleNum].code;
|
|
652
|
-
monomers[positions[i][0]] = monomers[positions[i][0]].replace(`(${code})`, '');
|
|
653
|
-
monomers[positions[i][1]] = monomers[positions[i][1]].replace(`(${code})`, '');
|
|
51
|
+
/** Get macromolecule from harmonized sequence (template) */
|
|
52
|
+
applyRules(rules: Rules): void {
|
|
53
|
+
const sequence = this.getNotation();
|
|
654
54
|
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
55
|
+
const [linkages, mainFragments] = handleDuplicated(sequence, rules);
|
|
56
|
+
const monomers = new Array<Array<string>>(mainFragments.length);
|
|
57
|
+
handleLinkRules(mainFragments, monomers, linkages, rules);
|
|
58
|
+
handleReactionRules(monomers, linkages, rules);
|
|
659
59
|
|
|
660
|
-
|
|
60
|
+
this.underRules = true;
|
|
61
|
+
this.linkagesUnderRules = linkages;
|
|
62
|
+
this.monomersUnderRules = monomers;
|
|
63
|
+
this.molUnderRules = getHelmMol(linkages, monomers, this.helmHelper);
|
|
661
64
|
}
|
|
662
65
|
|
|
663
66
|
public check(throwError: boolean = false): string[] {
|