@datagrok/sequence-translator 1.5.2 → 1.6.0

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.
@@ -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 {HelmTypes} from '@datagrok-libraries/bio/src/helm/consts';
4
- import {cleanupHelmSymbol} from '@datagrok-libraries/bio/src/helm/utils';
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
- constructor(
30
- monomers: string[][], linkages: Linkage[], mol: HelmMol,
31
- protected helmHelper: IHelmHelper,
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 = 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
- static fromNotation(sequence: string, rules: Rules, helmHelper: IHelmHelper): Chain {
122
- const heterodimerCode = rules.heterodimerCode;
123
- const homodimerCode = rules.homodimerCode;
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 notation (template) */
318
- static parseNotation(sequence: string, helmHelper: IHelmHelper): Chain {
319
- const mainFragments: string[][] = [];
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
- const atoms = this.mol.atoms;
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
- protected static getLinkedPositions(monomers: string[], rules: RuleLink[] | RuleReaction []):
525
- [number, number, number][] {
526
- const result: [number, number, number][] = [];
527
-
528
- for (let i = 0; i < rules.length; i++) {
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
- protected static getAllReactants(rules: RuleReaction[], monomers: string [], positions: [number, number, number][]):
640
- [string [], number [], number [], number []] {
641
- const allPos1: number [] = [];
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
- allPos1.push(positions[i][0] + 1);
656
- allPos2.push(positions[i][1] + 1);
657
- rule.push(positions[i][2]);
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
- return [monomers, allPos1, allPos2, rule];
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[] {