@datagrok/sequence-translator 1.4.8 → 1.5.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.
- package/.eslintrc.json +1 -1
- package/CHANGELOG.md +24 -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/files/polytool-rules/rules_example.json +35 -38
- package/package.json +9 -9
- package/src/apps/common/model/oligo-toolkit-package.ts +13 -7
- package/src/package.ts +8 -7
- package/src/polytool/const.ts +1 -0
- package/src/polytool/{pt-conversion.ts → conversion/pt-chain.ts} +118 -285
- package/src/polytool/conversion/pt-conversion.ts +26 -0
- package/src/polytool/conversion/pt-misc.ts +193 -0
- package/src/polytool/conversion/pt-rules.ts +231 -0
- package/src/polytool/conversion/rule-manager.ts +205 -0
- package/src/polytool/pt-convert-editor.ts +1 -1
- package/src/polytool/pt-dialog.ts +133 -6
- package/src/polytool/{pt-enumeration-helm-dialog.ts → pt-enumerate-seq-dialog.ts} +243 -114
- package/src/polytool/pt-enumeration-helm.ts +2 -2
- package/src/polytool/pt-placeholders-breadth-input.ts +80 -39
- package/src/polytool/pt-placeholders-input.ts +96 -35
- package/src/polytool/pt-unrule-dialog.ts +1 -1
- package/src/polytool/pt-unrule.ts +2 -2
- package/src/polytool/types.ts +5 -1
- package/src/tests/polytool-chain-from-notation-tests.ts +9 -18
- package/src/tests/polytool-chain-parse-notation-tests.ts +3 -2
- package/src/tests/polytool-convert-tests.ts +5 -3
- package/src/tests/polytool-unrule-tests.ts +1 -1
- package/src/tests/toAtomicLevel-tests.ts +5 -6
- package/src/utils/cell-renderer-cyclized.ts +37 -0
- package/src/utils/context-menu.ts +1 -1
- package/src/utils/cyclized.ts +23 -26
- package/src/polytool/pt-rules.ts +0 -93
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import * as ui from 'datagrok-api/ui';
|
|
3
|
-
import * as DG from 'datagrok-api/dg';
|
|
4
|
-
|
|
5
|
-
import wu from 'wu';
|
|
6
|
-
|
|
7
|
-
import {cleanupHelmSymbol} from '@datagrok-libraries/bio/src/helm/utils';
|
|
8
|
-
import {HelmTypes, PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
|
|
9
|
-
import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
10
|
-
import {IMonomerLib, IMonomerLibBase, Monomer, MonomerLibData, RGroup} from '@datagrok-libraries/bio/src/types';
|
|
11
|
-
import {RDModule, RDMol, RDReaction, MolList, RDReactionResult} from '@datagrok-libraries/chem-meta/src/rdkit-api';
|
|
12
|
-
import {HELM_REQUIRED_FIELD as REQ, HELM_OPTIONAL_FIELDS as OPT, HELM_RGROUP_FIELDS, HELM_OPTIONAL_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
|
|
13
|
-
import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
|
|
14
|
-
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
15
|
-
import {HelmAtom, HelmBio, HelmMol, HelmType, JSDraw2ModuleType, OrgType} from '@datagrok-libraries/bio/src/helm/types';
|
|
1
|
+
import {Atom, IHelmBio, HelmMol, HelmType, JSDraw2ModuleType, OrgType} from '@datagrok-libraries/bio/src/helm/types';
|
|
16
2
|
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';
|
|
17
5
|
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
|
|
21
|
-
import {_package} from '../package';
|
|
6
|
+
import {getOuterIdx, getInnerIdx} from './pt-misc';
|
|
7
|
+
import {Rules, RuleLink, RuleReaction, getMonomerPairs} from './pt-rules';
|
|
22
8
|
|
|
23
9
|
declare const JSDraw2: JSDraw2ModuleType;
|
|
24
10
|
declare const org: OrgType;
|
|
@@ -31,8 +17,9 @@ type Linkage = {
|
|
|
31
17
|
fR: number,
|
|
32
18
|
sR: number
|
|
33
19
|
}
|
|
20
|
+
export type PtBio = IHelmBio & { i: number, j: number };
|
|
34
21
|
|
|
35
|
-
type
|
|
22
|
+
type PtAtom = Atom<HelmType, PtBio>
|
|
36
23
|
|
|
37
24
|
export class Chain {
|
|
38
25
|
linkages: Linkage[];
|
|
@@ -40,9 +27,9 @@ export class Chain {
|
|
|
40
27
|
mol: HelmMol;
|
|
41
28
|
|
|
42
29
|
constructor(
|
|
43
|
-
monomers: string[][],
|
|
44
|
-
|
|
45
|
-
|
|
30
|
+
monomers: string[][], linkages: Linkage[], mol: HelmMol,
|
|
31
|
+
protected helmHelper: IHelmHelper,
|
|
32
|
+
) {
|
|
46
33
|
this.linkages = linkages;
|
|
47
34
|
this.monomers = monomers;
|
|
48
35
|
this.mol = mol;
|
|
@@ -73,14 +60,14 @@ export class Chain {
|
|
|
73
60
|
monomers[i] = rawFragments[i].slice(idxStart + 1, idxEnd).split('.').map((s) => cleanupHelmSymbol(s));
|
|
74
61
|
for (let j = 0; j < monomers[i].length; j++) {
|
|
75
62
|
const elem = monomers[i][j];
|
|
76
|
-
const bio:
|
|
77
|
-
const atom = new JSDraw2.Atom<HelmType>(p, elem, bio);
|
|
63
|
+
const bio: PtBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
|
|
64
|
+
const atom = new JSDraw2.Atom<HelmType, IHelmBio>(p, elem, bio);
|
|
78
65
|
resMol.addAtom(atom);
|
|
79
66
|
|
|
80
67
|
if (j !== 0) {
|
|
81
68
|
const atom1 = resMol.atoms[counter - 1];
|
|
82
69
|
const atom2 = resMol.atoms[counter];
|
|
83
|
-
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
70
|
+
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
84
71
|
bond.r1 = 2;
|
|
85
72
|
bond.r2 = 1;
|
|
86
73
|
resMol.addBond(bond);
|
|
@@ -116,29 +103,21 @@ export class Chain {
|
|
|
116
103
|
for (let i = 0; i < linkages.length; i++) {
|
|
117
104
|
const atom1 = resMol.atoms[linkages[i].fMonomer - 1];
|
|
118
105
|
const atom2 = resMol.atoms[linkages[i].sMonomer - 1];
|
|
119
|
-
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
106
|
+
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
120
107
|
bond.r1 = linkages[i].fR;
|
|
121
108
|
bond.r2 = linkages[i].sR;
|
|
122
109
|
resMol.addBond(bond);
|
|
123
110
|
}
|
|
124
111
|
|
|
125
|
-
return new Chain(monomers, linkages, resMol);
|
|
112
|
+
return new Chain(monomers, linkages, resMol, helmHelper);
|
|
126
113
|
}
|
|
127
114
|
|
|
128
115
|
/** Get macromolecule from harmonized sequence (template) */
|
|
129
116
|
applyRules(rules: Rules): Chain {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
const resLinkages: Linkage[] = [...this.linkages];
|
|
133
|
-
const resMol: HelmMol = this.mol.clone();
|
|
134
|
-
|
|
135
|
-
throw new Error('not implemented');
|
|
136
|
-
|
|
137
|
-
const chain = new Chain(resMonomers, resLinkages, resMol);
|
|
138
|
-
return chain;
|
|
117
|
+
const newNotation = this.getNotation();
|
|
118
|
+
return Chain.fromNotation(newNotation, rules, this.helmHelper);
|
|
139
119
|
}
|
|
140
120
|
|
|
141
|
-
/** @deprecated Use {@link parseNotation} and {@link applyRules} instead. */
|
|
142
121
|
static fromNotation(sequence: string, rules: Rules, helmHelper: IHelmHelper): Chain {
|
|
143
122
|
const heterodimerCode = rules.heterodimerCode;
|
|
144
123
|
const homodimerCode = rules.homodimerCode;
|
|
@@ -230,14 +209,14 @@ export class Chain {
|
|
|
230
209
|
const ch2 = new Array<string>(monomersCycled.length - allPos2[0]);
|
|
231
210
|
for (let j = 0; j < allPos2[0] - 1; j++) {
|
|
232
211
|
const elem = ch1[j] = monomersCycled[j];
|
|
233
|
-
const bio:
|
|
234
|
-
const atom:
|
|
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);
|
|
235
214
|
resMol.addAtom(atom);
|
|
236
215
|
|
|
237
216
|
if (j > 0) {
|
|
238
217
|
const atom1 = resMol.atoms[counter - 1];
|
|
239
218
|
const atom2 = resMol.atoms[counter];
|
|
240
|
-
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
219
|
+
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
241
220
|
bond.r1 = 2;
|
|
242
221
|
bond.r2 = 1;
|
|
243
222
|
resMol.addBond(bond);
|
|
@@ -247,14 +226,14 @@ export class Chain {
|
|
|
247
226
|
|
|
248
227
|
for (let j = allPos2[0]; j < monomersCycled.length; j++) {
|
|
249
228
|
const elem = ch2[j - allPos2[0]] = monomersCycled[j];
|
|
250
|
-
const bio:
|
|
251
|
-
const atom:
|
|
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);
|
|
252
231
|
resMol.addAtom(atom);
|
|
253
232
|
|
|
254
233
|
if (j > allPos2[0]) {
|
|
255
234
|
const atom1 = resMol.atoms[counter - 1];
|
|
256
235
|
const atom2 = resMol.atoms[counter];
|
|
257
|
-
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
236
|
+
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
258
237
|
bond.r1 = 2;
|
|
259
238
|
bond.r2 = 1;
|
|
260
239
|
resMol.addBond(bond);
|
|
@@ -304,14 +283,14 @@ export class Chain {
|
|
|
304
283
|
} else {
|
|
305
284
|
for (let j = 0; j < monomers[i].length; j++) {
|
|
306
285
|
const elem = monomers[i][j];
|
|
307
|
-
const bio:
|
|
308
|
-
const atom:
|
|
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);
|
|
309
288
|
resMol.addAtom(atom);
|
|
310
289
|
|
|
311
290
|
if (j > 0) {
|
|
312
291
|
const atom1 = resMol.atoms[counter - 1];
|
|
313
292
|
const atom2 = resMol.atoms[counter];
|
|
314
|
-
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
293
|
+
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
315
294
|
bond.r1 = 2;
|
|
316
295
|
bond.r2 = 1;
|
|
317
296
|
resMol.addBond(bond);
|
|
@@ -325,13 +304,13 @@ export class Chain {
|
|
|
325
304
|
for (const l of linkages) {
|
|
326
305
|
const atom1 = resMol.atoms[l.fMonomer - 1];
|
|
327
306
|
const atom2 = resMol.atoms[l.sMonomer - 1];
|
|
328
|
-
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
307
|
+
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
329
308
|
bond.r1 = l.fR;
|
|
330
309
|
bond.r2 = l.sR;
|
|
331
310
|
resMol.addBond(bond);
|
|
332
311
|
}
|
|
333
312
|
|
|
334
|
-
const chain = new Chain(monomersAll, linkages, resMol);
|
|
313
|
+
const chain = new Chain(monomersAll, linkages, resMol, helmHelper);
|
|
335
314
|
return chain;
|
|
336
315
|
}
|
|
337
316
|
|
|
@@ -382,14 +361,14 @@ export class Chain {
|
|
|
382
361
|
for (let j = 0; j < mainFragments[i].length; j++) {
|
|
383
362
|
if (!!mainFragments[i][j]) {
|
|
384
363
|
const elem = mainFragments[i][j];
|
|
385
|
-
const bio:
|
|
386
|
-
const atom = new JSDraw2.Atom<HelmType>(p, elem, bio);
|
|
364
|
+
const bio: PtBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
|
|
365
|
+
const atom = new JSDraw2.Atom<HelmType, IHelmBio>(p, elem, bio);
|
|
387
366
|
resMol.addAtom(atom);
|
|
388
367
|
|
|
389
368
|
if (j !== 0) {
|
|
390
369
|
const atom1 = resMol.atoms[counter - 1];
|
|
391
370
|
const atom2 = resMol.atoms[counter];
|
|
392
|
-
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
371
|
+
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
393
372
|
bond.r1 = 2;
|
|
394
373
|
bond.r2 = 1;
|
|
395
374
|
resMol.addBond(bond);
|
|
@@ -405,13 +384,13 @@ export class Chain {
|
|
|
405
384
|
for (let i = 0; i < linkages.length; i++) {
|
|
406
385
|
const atom1 = resMol.atoms[linkages[i].fMonomer - 1];
|
|
407
386
|
const atom2 = resMol.atoms[linkages[i].sMonomer - 1];
|
|
408
|
-
const bond = new JSDraw2.Bond<HelmType>(atom1, atom2);
|
|
387
|
+
const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
|
|
409
388
|
bond.r1 = linkages[i].fR;
|
|
410
389
|
bond.r2 = linkages[i].sR;
|
|
411
390
|
resMol.addBond(bond);
|
|
412
391
|
}
|
|
413
392
|
|
|
414
|
-
const chain = new Chain(mainFragments, linkages, resMol);
|
|
393
|
+
const chain = new Chain(mainFragments, linkages, resMol, helmHelper);
|
|
415
394
|
return chain;
|
|
416
395
|
}
|
|
417
396
|
|
|
@@ -544,7 +523,7 @@ export class Chain {
|
|
|
544
523
|
|
|
545
524
|
protected static getLinkedPositions(monomers: string[], rules: RuleLink[] | RuleReaction []):
|
|
546
525
|
[number, number, number][] {
|
|
547
|
-
const result: [number, number, number][] =
|
|
526
|
+
const result: [number, number, number][] = [];
|
|
548
527
|
|
|
549
528
|
for (let i = 0; i < rules.length; i++) {
|
|
550
529
|
let firstFound = false;
|
|
@@ -553,42 +532,78 @@ export class Chain {
|
|
|
553
532
|
let firstEntryIndex = -1;
|
|
554
533
|
let secondEntryIndex = -1;
|
|
555
534
|
const add = `(${rules[i].code})`;
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
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
|
+
}
|
|
569
567
|
}
|
|
570
|
-
}
|
|
571
|
-
|
|
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 {
|
|
572
593
|
firstFound = true;
|
|
573
594
|
firstIsFirst = true;
|
|
574
|
-
firstEntryIndex =
|
|
575
|
-
} else if (monomers[j] == rules[i].secondMonomer + add) {
|
|
576
|
-
firstFound = true;
|
|
577
|
-
firstIsFirst = false;
|
|
578
|
-
firstEntryIndex = j;
|
|
579
|
-
} else {
|
|
580
|
-
continue;
|
|
595
|
+
firstEntryIndex = k;
|
|
581
596
|
}
|
|
582
597
|
}
|
|
583
598
|
}
|
|
584
|
-
}
|
|
585
599
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
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
|
+
}
|
|
592
607
|
}
|
|
593
608
|
|
|
594
609
|
return result;
|
|
@@ -600,21 +615,22 @@ export class Chain {
|
|
|
600
615
|
const allPos2: number [] = [];
|
|
601
616
|
const allAttaches1: number [] = [];
|
|
602
617
|
const allAttaches2: number [] = [];
|
|
603
|
-
const
|
|
618
|
+
const count = positions.length;
|
|
604
619
|
|
|
605
|
-
for (let i = 0; i <
|
|
620
|
+
for (let i = 0; i < count; i++) {
|
|
606
621
|
if (positions[i][0] == -1)
|
|
607
622
|
continue;
|
|
608
623
|
|
|
609
|
-
const
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
monomers[positions[i][
|
|
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})`, '');
|
|
613
629
|
|
|
614
630
|
allPos1.push(positions[i][0] + 1);
|
|
615
631
|
allPos2.push(positions[i][1] + 1);
|
|
616
|
-
allAttaches1.push(rules[
|
|
617
|
-
allAttaches2.push(rules[
|
|
632
|
+
allAttaches1.push(rules[ruleNum].firstLinkingGroup);
|
|
633
|
+
allAttaches2.push(rules[ruleNum].secondLinkingGroup);
|
|
618
634
|
}
|
|
619
635
|
|
|
620
636
|
return [monomers, allPos1, allPos2, allAttaches1, allAttaches2];
|
|
@@ -625,16 +641,16 @@ export class Chain {
|
|
|
625
641
|
const allPos1: number [] = [];
|
|
626
642
|
const allPos2: number [] = [];
|
|
627
643
|
const rule: number [] = [];
|
|
628
|
-
const
|
|
644
|
+
const count = positions.length;
|
|
629
645
|
|
|
630
|
-
for (let i = 0; i <
|
|
646
|
+
for (let i = 0; i < count; i++) {
|
|
631
647
|
if (positions[i][0] == -1)
|
|
632
648
|
continue;
|
|
633
649
|
|
|
634
|
-
const
|
|
635
|
-
const
|
|
636
|
-
monomers[positions[i][0]] = monomers[positions[i][0]].replace(
|
|
637
|
-
monomers[positions[i][1]] = monomers[positions[i][1]].replace(
|
|
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})`, '');
|
|
638
654
|
|
|
639
655
|
allPos1.push(positions[i][0] + 1);
|
|
640
656
|
allPos2.push(positions[i][1] + 1);
|
|
@@ -648,15 +664,17 @@ export class Chain {
|
|
|
648
664
|
const errors: string[] = [];
|
|
649
665
|
|
|
650
666
|
const chainsMonomerCount = this.monomers.map((ch) => ch.length).reduce((acc, curr) => acc + curr, 0);
|
|
651
|
-
if (this.mol.atoms.length !== chainsMonomerCount)
|
|
667
|
+
if (this.mol.atoms.length !== chainsMonomerCount) {
|
|
652
668
|
errors.push(`The mol atoms count ${this.mol.atoms.length} does not match ` +
|
|
653
669
|
`the total number ${chainsMonomerCount} of chains' monomers.`);
|
|
670
|
+
}
|
|
654
671
|
|
|
655
672
|
const internalBondsCount = this.monomers.map((ch) => ch.length - 1).reduce((acc, curr) => acc + curr, 0);
|
|
656
673
|
const chainsBondCount = internalBondsCount + this.linkages.length;
|
|
657
|
-
if (this.mol.bonds.length !== chainsBondCount)
|
|
674
|
+
if (this.mol.bonds.length !== chainsBondCount) {
|
|
658
675
|
errors.push(`The mol bonds count ${this.mol.bonds.length} does not match ` +
|
|
659
676
|
`the total number ${chainsBondCount} in- and inter-chain linkages.`);
|
|
677
|
+
}
|
|
660
678
|
|
|
661
679
|
let counter: number = 0;
|
|
662
680
|
for (let spIdx = 0; spIdx < this.monomers.length; ++spIdx) {
|
|
@@ -677,188 +695,3 @@ export class Chain {
|
|
|
677
695
|
return errors;
|
|
678
696
|
}
|
|
679
697
|
}
|
|
680
|
-
|
|
681
|
-
/** The main PolyTool convert engine. Returns list of Helms. Covered with tests. */
|
|
682
|
-
export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper: IHelmHelper): string[] {
|
|
683
|
-
const helms = new Array<string>(sequences.length);
|
|
684
|
-
for (let i = 0; i < sequences.length; i++) {
|
|
685
|
-
try {
|
|
686
|
-
if (sequences[i] == null) { helms[i] = ''; } else {
|
|
687
|
-
const chain = Chain.fromNotation(sequences[i], rules, helmHelper);
|
|
688
|
-
helms[i] = chain.getHelm();
|
|
689
|
-
}
|
|
690
|
-
} catch (err: any) {
|
|
691
|
-
const [errMsg, errStack] = errInfo(err);
|
|
692
|
-
_package.logger.error(errMsg, undefined, errStack);
|
|
693
|
-
helms[i] = '';
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
return helms;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
function getMonomersMolBlocks(monomer1: Monomer, monomer2: Monomer): [string, string] {
|
|
700
|
-
const mb1 = monomer1.molfile;
|
|
701
|
-
let mb2 = monomer2.molfile;
|
|
702
|
-
const addGroups = monomer1.rgroups.length;
|
|
703
|
-
|
|
704
|
-
//mol v2000 monomer
|
|
705
|
-
const rgpIdx = mb2.indexOf('M RGP');
|
|
706
|
-
if (rgpIdx !== -1) {
|
|
707
|
-
const groupsCountStr = mb2.substring(rgpIdx + 6, rgpIdx + 9);
|
|
708
|
-
const groupsCount = Number(groupsCountStr);
|
|
709
|
-
|
|
710
|
-
for (let i = 0; i < groupsCount; i++) {
|
|
711
|
-
const start = rgpIdx + 9 + 4 + i * 8;
|
|
712
|
-
const end = rgpIdx + 9 + 8 + i * 8;
|
|
713
|
-
const rGroupSpecifier = mb2.substring(start, end);
|
|
714
|
-
const groupPosition = Number(rGroupSpecifier) + addGroups;
|
|
715
|
-
const digits = Math.floor(Math.log10(groupPosition) + 1);
|
|
716
|
-
const newSpecifier = ' '.repeat(4 - digits) + String(groupPosition);
|
|
717
|
-
mb2 = mb2.substring(0, start) + newSpecifier + mb2.substring(end, mb2.length);
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
//TODO: same for v3000 monomer
|
|
722
|
-
|
|
723
|
-
return [mb1, mb2];
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
function getSyntheticMolBlock(rdkit: RDModule, reaction: string,
|
|
727
|
-
mb1: string, mb2: string, monomerName: string): string {
|
|
728
|
-
let rxn: RDReaction | null = null;
|
|
729
|
-
let mols: MolList | null = null;
|
|
730
|
-
let mol1: RDMol | null = null;
|
|
731
|
-
let mol2: RDMol | null = null;
|
|
732
|
-
let rctns: RDReactionResult | null = null;
|
|
733
|
-
let molP: RDMol | null = null;
|
|
734
|
-
let molBlock = '';
|
|
735
|
-
|
|
736
|
-
try {
|
|
737
|
-
rxn = rdkit.get_rxn(reaction);
|
|
738
|
-
if (!rxn) throw new InvalidReactionError(reaction);
|
|
739
|
-
mols = new rdkit.MolList();
|
|
740
|
-
mol1 = rdkit.get_mol(mb1!);
|
|
741
|
-
mol2 = rdkit.get_mol(mb2!);
|
|
742
|
-
mols.append(mol1!);
|
|
743
|
-
mols.append(mol2!);
|
|
744
|
-
|
|
745
|
-
rctns = rxn.run_reactants(mols, 1);
|
|
746
|
-
//const size = rctns.size();
|
|
747
|
-
const element = rctns.get(0);
|
|
748
|
-
|
|
749
|
-
molP = element.next();
|
|
750
|
-
molBlock = molP?.get_molblock();//molP?.get_v3Kmolblock();//
|
|
751
|
-
} catch (err: any) {
|
|
752
|
-
const [errMsg, _errStack] = errInfo(err);
|
|
753
|
-
grok.shell.error(`Can not assemble monomer '${monomerName}': ${errMsg}.`);
|
|
754
|
-
throw err;
|
|
755
|
-
} finally {
|
|
756
|
-
rxn?.delete();
|
|
757
|
-
mols?.delete();
|
|
758
|
-
mol1?.delete();
|
|
759
|
-
mol2?.delete();
|
|
760
|
-
rctns?.delete();
|
|
761
|
-
molP?.delete();
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
return molBlock;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
function getNewGroups(monomer1: Monomer, monomer2: Monomer): RGroup[] {
|
|
768
|
-
const groups = new Array<RGroup>(monomer1?.rgroups.length! + monomer2?.rgroups.length!);
|
|
769
|
-
const length1 = monomer1?.rgroups.length!;
|
|
770
|
-
const length2 = monomer2?.rgroups.length!;
|
|
771
|
-
|
|
772
|
-
for (let i = 0; i < length1; i++)
|
|
773
|
-
groups[i] = monomer1?.rgroups[i]!;
|
|
774
|
-
|
|
775
|
-
for (let i = 0; i < length2; i++) {
|
|
776
|
-
const rGroupSpecifier = monomer2?.rgroups[i]!.label.replace('R', '');
|
|
777
|
-
const groupPosition = Number(rGroupSpecifier) + length1;
|
|
778
|
-
const group: RGroup = {
|
|
779
|
-
//@ts-ignore
|
|
780
|
-
[HELM_RGROUP_FIELDS.CAP_GROUP_SMILES_UPPERCASE]: monomer2?.rgroups[i].capGroupSMILES.replace(rGroupSpecifier, String(groupPosition)),
|
|
781
|
-
[HELM_RGROUP_FIELDS.ALTERNATE_ID]: monomer2?.rgroups[i].alternateId.replace(rGroupSpecifier, String(groupPosition)),
|
|
782
|
-
[HELM_RGROUP_FIELDS.CAP_GROUP_NAME]: monomer2?.rgroups[i].capGroupName,
|
|
783
|
-
[HELM_RGROUP_FIELDS.LABEL]: monomer2?.rgroups[i].label.replace(rGroupSpecifier, String(groupPosition)),
|
|
784
|
-
};
|
|
785
|
-
|
|
786
|
-
groups[i + length1] = group;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
return groups;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
export function getNewMonomer(rdkit: RDModule, mLib: IMonomerLib, rule: RuleReaction): [string, Monomer] {
|
|
793
|
-
const reacSmarts = rule.reaction;
|
|
794
|
-
const monomerName = rule.name;
|
|
795
|
-
|
|
796
|
-
const monomer1 = mLib.getMonomer('PEPTIDE', rule.firstMonomer);
|
|
797
|
-
if (!monomer1) throw new MonomerNotFoundError('PEPTIDE', rule.firstMonomer);
|
|
798
|
-
const monomer2 = mLib.getMonomer('PEPTIDE', rule.secondMonomer);
|
|
799
|
-
if (!monomer2) throw new MonomerNotFoundError('PEPTIDE', rule.secondMonomer);
|
|
800
|
-
|
|
801
|
-
const [mb1, mb2] = getMonomersMolBlocks(monomer1!, monomer2!);
|
|
802
|
-
const molBlock = getSyntheticMolBlock(rdkit, reacSmarts, mb1, mb2, monomerName);
|
|
803
|
-
const groups: RGroup[] = getNewGroups(monomer1!, monomer2!);
|
|
804
|
-
|
|
805
|
-
const resMonomer: Monomer = {
|
|
806
|
-
[REQ.SYMBOL]: monomerName,
|
|
807
|
-
[REQ.NAME]: monomerName,
|
|
808
|
-
[REQ.MOLFILE]: molBlock,
|
|
809
|
-
[REQ.AUTHOR]: '',
|
|
810
|
-
[REQ.ID]: 0,
|
|
811
|
-
[REQ.RGROUPS]: groups,
|
|
812
|
-
[REQ.SMILES]: '',
|
|
813
|
-
[REQ.POLYMER_TYPE]: 'PEPTIDE',
|
|
814
|
-
[REQ.MONOMER_TYPE]: 'Backbone',
|
|
815
|
-
[REQ.CREATE_DATE]: null,
|
|
816
|
-
|
|
817
|
-
// // @ts-ignore
|
|
818
|
-
// lib: {source: 'Reaction'},
|
|
819
|
-
};
|
|
820
|
-
|
|
821
|
-
resMonomer[OPT.META] = Object.assign(resMonomer[OPT.META] ?? {},
|
|
822
|
-
{'colors': {'default': {line: '#2083D5', text: '#2083D5', background: '#F2F2F5'}}});
|
|
823
|
-
|
|
824
|
-
return [monomerName, resMonomer];
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
export async function getOverriddenLibrary(rules: Rules): Promise<IMonomerLibBase> {
|
|
828
|
-
const monomerLibHelper = await getMonomerLibHelper();
|
|
829
|
-
const systemMonomerLib = monomerLibHelper.getMonomerLib();
|
|
830
|
-
|
|
831
|
-
const rdkit = await getRdKitModule();
|
|
832
|
-
const argLib: { [symbol: string]: Monomer } = {};
|
|
833
|
-
|
|
834
|
-
for (let i = 0; i < rules.reactionRules.length; i++) {
|
|
835
|
-
const [name, monomer] = getNewMonomer(rdkit, systemMonomerLib, rules.reactionRules[i]);
|
|
836
|
-
argLib[name] = monomer;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
const overrideMonomerLibData: MonomerLibData = {[PolymerTypes.PEPTIDE]: argLib};
|
|
840
|
-
const overriddenMonomerLib = systemMonomerLib.override(overrideMonomerLibData,
|
|
841
|
-
'ST-PT-reactions.' + wu.repeat(1).map(() => Math.floor((Math.random() * 36)).toString(36)).take(4).toArray().join(''));
|
|
842
|
-
return overriddenMonomerLib;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
/** Gets 0-based in-index (simple polymer) of out-index (continuous) {@link idx} */
|
|
846
|
-
export function getInnerIdx(outIdx: number, monomers: string[][]): [number, number] {
|
|
847
|
-
// let prevSpCount = 0;
|
|
848
|
-
// for (let spI = 0; spI < monomers.length && idx >= (prevSpCount + monomers[spI].length); ++spI)
|
|
849
|
-
// prevSpCount += monomers[spI].length;
|
|
850
|
-
// return idx - prevSpCount;
|
|
851
|
-
let inIdx = outIdx;
|
|
852
|
-
let spIdx: number;
|
|
853
|
-
for (spIdx = 0; spIdx < monomers.length && inIdx >= monomers[spIdx].length; ++spIdx)
|
|
854
|
-
inIdx -= monomers[spIdx].length;
|
|
855
|
-
return [inIdx, spIdx];
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
/** Gets 0-based out-index of 0-based in-index {@link inIdx} monomer of simple polymer {@link spIdx} */
|
|
859
|
-
export function getOuterIdx(inIdx: number, spIdx: number, monomers: string[][]): number {
|
|
860
|
-
let outIdx = 0;
|
|
861
|
-
for (let i = 0; i < spIdx; ++i)
|
|
862
|
-
outIdx += monomers[i].length;
|
|
863
|
-
return outIdx + inIdx;
|
|
864
|
-
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
|
|
2
|
+
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
3
|
+
import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
4
|
+
|
|
5
|
+
import {Rules} from './pt-rules';
|
|
6
|
+
import {Chain} from './pt-chain';
|
|
7
|
+
|
|
8
|
+
import {_package} from '../../package';
|
|
9
|
+
|
|
10
|
+
/** The main PolyTool convert engine. Returns list of Helms. Covered with tests. */
|
|
11
|
+
export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper: IHelmHelper): string[] {
|
|
12
|
+
const helms = new Array<string>(sequences.length);
|
|
13
|
+
for (let i = 0; i < sequences.length; i++) {
|
|
14
|
+
try {
|
|
15
|
+
if (sequences[i] == null) { helms[i] = ''; } else {
|
|
16
|
+
const chain = Chain.fromNotation(sequences[i], rules, helmHelper);
|
|
17
|
+
helms[i] = chain.getHelm();
|
|
18
|
+
}
|
|
19
|
+
} catch (err: any) {
|
|
20
|
+
const [errMsg, errStack] = errInfo(err);
|
|
21
|
+
_package.logger.error(errMsg, undefined, errStack);
|
|
22
|
+
helms[i] = '';
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return helms;
|
|
26
|
+
}
|