@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.
Files changed (34) hide show
  1. package/.eslintrc.json +1 -1
  2. package/CHANGELOG.md +24 -0
  3. package/dist/package-test.js +1 -1
  4. package/dist/package-test.js.map +1 -1
  5. package/dist/package.js +1 -1
  6. package/dist/package.js.map +1 -1
  7. package/files/polytool-rules/rules_example.json +35 -38
  8. package/package.json +9 -9
  9. package/src/apps/common/model/oligo-toolkit-package.ts +13 -7
  10. package/src/package.ts +8 -7
  11. package/src/polytool/const.ts +1 -0
  12. package/src/polytool/{pt-conversion.ts → conversion/pt-chain.ts} +118 -285
  13. package/src/polytool/conversion/pt-conversion.ts +26 -0
  14. package/src/polytool/conversion/pt-misc.ts +193 -0
  15. package/src/polytool/conversion/pt-rules.ts +231 -0
  16. package/src/polytool/conversion/rule-manager.ts +205 -0
  17. package/src/polytool/pt-convert-editor.ts +1 -1
  18. package/src/polytool/pt-dialog.ts +133 -6
  19. package/src/polytool/{pt-enumeration-helm-dialog.ts → pt-enumerate-seq-dialog.ts} +243 -114
  20. package/src/polytool/pt-enumeration-helm.ts +2 -2
  21. package/src/polytool/pt-placeholders-breadth-input.ts +80 -39
  22. package/src/polytool/pt-placeholders-input.ts +96 -35
  23. package/src/polytool/pt-unrule-dialog.ts +1 -1
  24. package/src/polytool/pt-unrule.ts +2 -2
  25. package/src/polytool/types.ts +5 -1
  26. package/src/tests/polytool-chain-from-notation-tests.ts +9 -18
  27. package/src/tests/polytool-chain-parse-notation-tests.ts +3 -2
  28. package/src/tests/polytool-convert-tests.ts +5 -3
  29. package/src/tests/polytool-unrule-tests.ts +1 -1
  30. package/src/tests/toAtomicLevel-tests.ts +5 -6
  31. package/src/utils/cell-renderer-cyclized.ts +37 -0
  32. package/src/utils/context-menu.ts +1 -1
  33. package/src/utils/cyclized.ts +23 -26
  34. package/src/polytool/pt-rules.ts +0 -93
@@ -1,24 +1,10 @@
1
- import * as grok from 'datagrok-api/grok';
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 {Rules, RuleLink, RuleReaction} from './pt-rules';
19
- import {InvalidReactionError, MonomerNotFoundError} from './types';
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 PolyToolBio = HelmBio & { i: number, j: number };
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
- linkages: Linkage[],
45
- mol: HelmMol) {
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: PolyToolBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
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
- // Clone this
131
- const resMonomers: string[][] = this.monomers.map((mL) => [...mL]);
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: PolyToolBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
234
- const atom: HelmAtom = new JSDraw2.Atom<HelmType>(p, elem, bio);
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: PolyToolBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
251
- const atom: HelmAtom = new JSDraw2.Atom<HelmType>(p, elem, bio);
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: PolyToolBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
308
- const atom: HelmAtom = new JSDraw2.Atom<HelmType>(p, elem, bio);
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: PolyToolBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
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][] = new Array<[number, number, number]>(rules.length);
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
- for (let j = 0; j < monomers.length; j++) {
557
- if (monomers[j].includes(add)) {
558
- if (firstFound) {
559
- if (firstIsFirst && monomers[j] == rules[i].secondMonomer + add) {
560
- secondFound = true;
561
- secondEntryIndex = j;
562
- break;
563
- } else if (!firstIsFirst && monomers[j] == rules[i].firstMonomer + add) {
564
- secondFound = true;
565
- secondEntryIndex = j;
566
- break;
567
- } else {
568
- continue;
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
- } else {
571
- if (monomers[j] == rules[i].firstMonomer + add) {
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 = j;
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
- if (!(firstFound && secondFound))
587
- result[i] = [-1, -1, -1];
588
- else if (firstIsFirst)
589
- result[i] = [firstEntryIndex, secondEntryIndex, i];
590
- else
591
- result[i] = [secondEntryIndex, firstEntryIndex, i];
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 ruleCount = rules.length;
618
+ const count = positions.length;
604
619
 
605
- for (let i = 0; i < ruleCount; i++) {
620
+ for (let i = 0; i < count; i++) {
606
621
  if (positions[i][0] == -1)
607
622
  continue;
608
623
 
609
- const firstMonomer = monomers[positions[i][0]];
610
- const secondMonomer = monomers[positions[i][1]];
611
- monomers[positions[i][0]] = monomers[positions[i][0]].replace(firstMonomer, rules[i].firstSubstitution);
612
- monomers[positions[i][1]] = monomers[positions[i][1]].replace(secondMonomer, rules[i].secondSubstitution);
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[i].firstLinkingGroup);
617
- allAttaches2.push(rules[i].secondLinkingGroup);
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 ruleCount = rules.length;
644
+ const count = positions.length;
629
645
 
630
- for (let i = 0; i < ruleCount; i++) {
646
+ for (let i = 0; i < count; i++) {
631
647
  if (positions[i][0] == -1)
632
648
  continue;
633
649
 
634
- const firstMonomer = monomers[positions[i][0]];
635
- const secondMonomer = monomers[positions[i][1]];
636
- monomers[positions[i][0]] = monomers[positions[i][0]].replace(firstMonomer, rules[i].firstMonomer);
637
- monomers[positions[i][1]] = monomers[positions[i][1]].replace(secondMonomer, rules[i].secondMonomer);
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
+ }