@datagrok/sequence-translator 1.6.3 → 1.7.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.6.3",
4
+ "version": "1.7.0",
5
5
  "author": {
6
6
  "name": "Leonid Stolbov",
7
7
  "email": "lstolbov@datagrok.ai"
@@ -23,7 +23,7 @@
23
23
  ],
24
24
  "dependencies": {
25
25
  "@datagrok-libraries/bio": "^5.46.0",
26
- "@datagrok-libraries/chem-meta": "^1.2.7",
26
+ "@datagrok-libraries/chem-meta": "^1.2.8",
27
27
  "@datagrok-libraries/tutorials": "^1.4.3",
28
28
  "@datagrok-libraries/utils": "^4.3.7",
29
29
  "@types/react": "^18.0.15",
@@ -41,9 +41,9 @@
41
41
  "devDependencies": {
42
42
  "@datagrok-libraries/helm-web-editor": "^1.1.13",
43
43
  "@datagrok-libraries/js-draw-lite": "^0.0.10",
44
- "@datagrok/bio": "^2.17.2",
45
- "@datagrok/helm": "^2.5.8",
46
- "@datagrok/chem": "^1.12.4",
44
+ "@datagrok/bio": "^2.18.0",
45
+ "@datagrok/helm": "^2.7.0",
46
+ "@datagrok/chem": "^1.13.0",
47
47
  "@types/jquery": "^3.5.14",
48
48
  "@types/js-yaml": "^4.0.5",
49
49
  "@types/lodash": "^4.14.202",
package/src/package.ts CHANGED
@@ -49,7 +49,7 @@ async function initSequenceTranslatorInt(): Promise<void> {
49
49
 
50
50
  //name: Oligo Toolkit
51
51
  //meta.icon: img/icons/toolkit.png
52
- //meta.browsePath: Oligo
52
+ //meta.browsePath: Peptides | Oligo Toolkit
53
53
  //tags: app
54
54
  //output: view v
55
55
  export async function oligoToolkitApp(): Promise<DG.ViewBase> {
@@ -64,7 +64,7 @@ export async function oligoToolkitApp(): Promise<DG.ViewBase> {
64
64
 
65
65
  //name: Oligo Translator
66
66
  //meta.icon: img/icons/translator.png
67
- //meta.browsePath: Oligo
67
+ //meta.browsePath: Peptides | Oligo Toolkit
68
68
  //tags: app
69
69
  //output: view v
70
70
  export async function oligoTranslatorApp(): Promise<DG.ViewBase> {
@@ -74,7 +74,7 @@ export async function oligoTranslatorApp(): Promise<DG.ViewBase> {
74
74
 
75
75
  //name: Oligo Pattern
76
76
  //meta.icon: img/icons/pattern.png
77
- //meta.browsePath: Oligo
77
+ //meta.browsePath: Peptides | Oligo Toolkit
78
78
  //tags: app
79
79
  //output: view v
80
80
  export async function oligoPatternApp(): Promise<DG.ViewBase> {
@@ -84,7 +84,7 @@ export async function oligoPatternApp(): Promise<DG.ViewBase> {
84
84
 
85
85
  //name: Oligo Structure
86
86
  //meta.icon: img/icons/structure.png
87
- //meta.browsePath: Oligo
87
+ //meta.browsePath: Peptides | Oligo Toolkit
88
88
  //tags: app
89
89
  //output: view v
90
90
  export async function oligoStructureApp(): Promise<DG.ViewBase> {
@@ -209,7 +209,7 @@ export async function getPolyToolConvertEditor(call: DG.FuncCall): Promise<DG.Co
209
209
  export async function polyToolConvert2(table: DG.DataFrame,
210
210
  seqCol: DG.Column, generateHelm: boolean, chiralityEngine: boolean, rules: string[]
211
211
  ): Promise<DG.Column<string>> {
212
- const ptConvertRes = await polyToolConvert(seqCol, generateHelm, chiralityEngine, rules);
212
+ const ptConvertRes = await polyToolConvert(seqCol, generateHelm, false, chiralityEngine, false, rules);
213
213
  return ptConvertRes[0];
214
214
  }
215
215
 
@@ -273,17 +273,17 @@ export async function createMonomerLibraryForPolyTool(file: DG.FileInfo) {
273
273
  // }
274
274
  // }
275
275
 
276
- //name: PolyTool Enumerator Helm
276
+ //name: HELM Enumerator
277
277
  //meta.icon: img/icons/structure.png
278
- //meta.browsePath: PolyTool
278
+ //meta.browsePath: Peptides | PolyTool
279
279
  //tags: app
280
280
  export async function ptEnumeratorHelmApp(): Promise<void> {
281
281
  await polyToolEnumerateHelmUI();
282
282
  }
283
283
 
284
- //name: PolyTool Enumerator Chem
284
+ //name: Chem Enumerator
285
285
  //meta.icon: img/icons/structure.png
286
- //meta.browsePath: PolyTool
286
+ //meta.browsePath: Peptides | PolyTool
287
287
  //tags: app
288
288
  export async function ptEnumeratorChemApp(): Promise<void> {
289
289
  polyToolEnumerateChemUI();
@@ -32,6 +32,8 @@ export const PT_WARNING_COLUMN = 'No marcomolecule column chosen!';
32
32
 
33
33
  export const PT_UI_GET_HELM = 'Get HELM';
34
34
  export const PT_UI_ADD_HELM = 'Add HELM column';
35
+ export const PT_UI_LINEARIZE = 'Linearize';
36
+ export const PT_UI_LINEARIZE_TT = 'Make representation linear if possible';
35
37
  export const PT_UI_USE_CHIRALITY = 'Chirality engine';
36
38
  export const PT_UI_HIGHLIGHT_MONOMERS = 'Highlight monomers';
37
39
  export const PT_UI_DIALOG_CONVERSION = 'Poly Tool Conversion';
@@ -0,0 +1,70 @@
1
+ import * as DG from 'datagrok-api/dg';
2
+ import * as grok from 'datagrok-api/grok';
3
+
4
+ import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
5
+ import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
6
+ import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomic-level';
7
+ import {ALPHABET, NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
8
+ import {IMonomerLibBase} from '@datagrok-libraries/bio/src/types';
9
+ import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
10
+
11
+ export function dealGroups(col: DG.Column<string>): void {
12
+ for (let i = 0; i < col.length; i++) {
13
+ col.set(i, col.get(i)!.replaceAll('undefined', 'H'));
14
+ col.set(i, col.get(i)!.replaceAll('Oh', 'O'));
15
+ col.set(i, col.get(i)!.replaceAll('0.000000 3', '0.000000 0'));
16
+ col.set(i, col.get(i)!.replaceAll('?', 'O'));
17
+ col.set(i, col.get(i)!.replaceAll('0 3\n', '0 0\n'));
18
+ col.set(i, col.get(i)!.replaceAll('RGROUPS=(1 1)', ''));
19
+ }
20
+ }
21
+
22
+ export async function helmToMol(resHelmCol: DG.Column, resList: string[],
23
+ isLinear: boolean[], chiralityEngine: boolean, highlight: boolean, linearize: boolean,
24
+ lib: IMonomerLibBase, rdkit: RDModule, seqHelper: ISeqHelper) {
25
+ const getUnusedName = (df: DG.DataFrame | undefined, colName: string): string => {
26
+ if (!df) return colName;
27
+ return df.columns.getUnusedName(colName);
28
+ };
29
+
30
+ const toAtomicLevelRes =
31
+ await seqHelper.helmToAtomicLevel(resHelmCol, chiralityEngine, highlight, lib);
32
+
33
+ const resMolCol = toAtomicLevelRes.molCol!;
34
+
35
+ const allLinear = isLinear.filter((l) => l).length;
36
+ if (linearize && allLinear > 0) {
37
+ const lin = new Array<string>(allLinear);
38
+ let counter = 0;
39
+ for (let i = 0; i < isLinear.length; i++) {
40
+ if (isLinear[i]) {
41
+ lin[counter] = resList[i];
42
+ counter++;
43
+ }
44
+ }
45
+
46
+ const linCol = DG.Column.fromStrings('helm', lin);
47
+ linCol.semType = DG.SEMTYPE.MACROMOLECULE;
48
+ linCol.meta.units = NOTATION.HELM;
49
+ linCol.setTag(DG.TAGS.CELL_RENDERER, 'helm');
50
+
51
+ const monomerLibHelper = await getMonomerLibHelper();
52
+ const systemMonomerLib = monomerLibHelper.getMonomerLib();
53
+ try {
54
+ const linear = await _toAtomicLevel(DG.DataFrame.create(0), linCol, systemMonomerLib, seqHelper, rdkit);
55
+ counter = 0;
56
+ for (let i = 0; i < isLinear.length; i++) {
57
+ if (isLinear[i]) {
58
+ resMolCol.set(i, linear!.molCol!.get(counter));
59
+ counter++;
60
+ }
61
+ }
62
+ } catch (e: any) {
63
+ grok.shell.warning('PolyTool was not able to linearize sequences');
64
+ }
65
+ }
66
+
67
+ dealGroups(resMolCol);
68
+
69
+ return resMolCol;
70
+ }
@@ -16,6 +16,7 @@ export class Chain {
16
16
  linkagesUnderRules: Linkage[];
17
17
  monomersUnderRules: string[][];
18
18
  molUnderRules: HelmMol;
19
+ posToPosUnderRules: number[][] = [];
19
20
 
20
21
  constructor(monomers: string[][], linkages: Linkage[], protected helmHelper: IHelmHelper) {
21
22
  this.linkages = linkages;
@@ -52,9 +53,28 @@ export class Chain {
52
53
  applyRules(rules: Rules): void {
53
54
  const sequence = this.getNotation();
54
55
 
55
- const [linkages, mainFragments] = handleDuplicated(sequence, rules);
56
+ const [linkages, mainFragments, isDuplicated] = handleDuplicated(sequence, rules);
56
57
  const monomers = new Array<Array<string>>(mainFragments.length);
57
- handleLinkRules(mainFragments, monomers, linkages, rules);
58
+
59
+ let counter = 0;
60
+ for (let i = 0; i < mainFragments.length; i++) {
61
+ monomers[i] = mainFragments[i].split('-');
62
+ if (!isDuplicated[i]) {
63
+ for (let j = 0; j < monomers[i].length; j++) {
64
+ this.posToPosUnderRules.push([counter]);
65
+ counter++;
66
+ }
67
+ } else {
68
+ const start = this.posToPosUnderRules.length - monomers[i].length;
69
+ for (let j = 0; j < monomers[i].length; j++) {
70
+ this.posToPosUnderRules[start + j].push(counter);
71
+ counter++;
72
+ }
73
+ }
74
+ }
75
+
76
+ //his.posToPosUnderRules
77
+ handleLinkRules(monomers, linkages, rules);
58
78
  handleReactionRules(monomers, linkages, rules);
59
79
 
60
80
  this.underRules = true;
@@ -6,14 +6,19 @@ import {Chain} from './pt-chain';
6
6
  import {_package} from '../../package';
7
7
 
8
8
  /** The main PolyTool convert engine. Returns list of Helms. Covered with tests. */
9
- export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper: IHelmHelper): string[] {
9
+ export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper: IHelmHelper):
10
+ [string[], boolean[], number[][][]] {
10
11
  const helms = new Array<string>(sequences.length);
12
+ const isLinear = new Array<boolean>(sequences.length);
13
+ const positionMaps = new Array<number[][]>(sequences.length);
11
14
  for (let i = 0; i < sequences.length; i++) {
12
15
  try {
13
16
  if (sequences[i] == null) { helms[i] = ''; } else {
14
17
  const chain = Chain.fromSeparator(sequences[i], helmHelper);
15
18
  chain.applyRules(rules);
19
+ isLinear[i] = chain.monomersUnderRules.length > 1 || chain.linkagesUnderRules.length > 0 ? false : true;
16
20
  helms[i] = chain.getHelm();
21
+ positionMaps[i] = chain.posToPosUnderRules;
17
22
  }
18
23
  } catch (err: any) {
19
24
  const [errMsg, errStack] = errInfo(err);
@@ -21,5 +26,5 @@ export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper:
21
26
  helms[i] = '';
22
27
  }
23
28
  }
24
- return helms;
29
+ return [helms, isLinear, positionMaps];
25
30
  }
@@ -0,0 +1,160 @@
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
+ import './style.css';
5
+
6
+ import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
7
+ import {Rules} from './pt-rules';
8
+ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
9
+ import {doPolyToolConvert} from './pt-conversion';
10
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
11
+ import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
12
+ import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
13
+ import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
14
+ import {getOverriddenLibrary} from './pt-synthetic';
15
+ import {helmToMol} from './pt-atomic';
16
+
17
+ class MonomerCard {
18
+ root: HTMLElement = ui.divV([], {classes: 'monomer-card-rule-root'});
19
+
20
+ private _selected: boolean = false;
21
+ get selected(): boolean { return this._selected; }
22
+ set selected(value: boolean) {
23
+ this._selected = value;
24
+ this.root.style.border = value ? '2px solid var(--green-2)' : '2px solid var(--grey-2)';
25
+ }
26
+
27
+ constructor(public monomer: Monomer | null) {}
28
+
29
+ render() {
30
+ if (this.monomer) {
31
+ ui.empty(this.root);
32
+ const monomerMolSvg = this.monomer.smiles && grok.chem.checkSmiles(this.monomer.smiles) ?
33
+ grok.chem.drawMolecule(this.monomer.smiles, 150, 120) :
34
+ grok.chem.drawMolecule(this.monomer.molfile ?? '', 150, 120);
35
+ this.root.appendChild(monomerMolSvg);
36
+ const monomerName =
37
+ ui.divH([ui.divText('Monomer Name: '), ui.divText(this.monomer.name)], {classes: 'monomer-card-info-rules'});
38
+
39
+ this.root.appendChild(monomerName);
40
+ ui.tooltip.bind(monomerName, this.monomer.name);
41
+ if (this.monomer.lib?.source) {
42
+ const monomerSource =
43
+ ui.divH([ui.divText('Source: '), ui.divText(this.monomer.lib.source)], {classes: 'monomer-card-info-rules'});
44
+ this.root.appendChild(monomerSource);
45
+ ui.tooltip.bind(monomerSource, this.monomer.lib.source);
46
+ }
47
+ const monomerType = ui.divH([
48
+ ui.divText('Polymer Type: '),
49
+ ui.divText(this.monomer.polymerType)
50
+ ], {classes: 'monomer-card-info-rules'});
51
+ this.root.appendChild(monomerType);
52
+ ui.tooltip.bind(monomerType, this.monomer.polymerType);
53
+
54
+ ui.tooltip.bind(this.root, 'Select Monomer');
55
+ }
56
+ }
57
+ }
58
+
59
+ export class RuleCards {
60
+ root: HTMLElement = ui.divH([],
61
+ {style: {
62
+ alignItems: 'center',
63
+ width: '100%',
64
+ overflow: 'hidden',
65
+ visibility: 'visible',
66
+ }, classes: 'monomer-cards'}
67
+ );
68
+ cardsFirst: MonomerCard[];
69
+ cardsSecond: MonomerCard[];
70
+ firstCard: MonomerCard;
71
+ secondCard: MonomerCard;
72
+ resulting: HTMLElement;
73
+ actionable: boolean;
74
+
75
+ constructor(public firstMonomers: string[], public secondMonomers: string[],
76
+ lib: IMonomerLib, public code: number, public rules: Rules) {
77
+ if (firstMonomers.length > 0) {
78
+ this.actionable = true;
79
+ const monomerGalleryFirst = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
80
+ const monomerGallerySecond = ui.divH([], {style: {overflowX: 'auto', width: '100%'}});
81
+ this.resulting = ui.divH([], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}});
82
+ const galleries = ui.divV([monomerGalleryFirst, monomerGallerySecond, this.resulting]);
83
+ this.cardsFirst = firstMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol)));
84
+ this.cardsSecond = secondMonomers.map((symbol) => new MonomerCard(lib.getMonomer('PEPTIDE', symbol)));
85
+
86
+ this.cardsFirst.forEach((card) => {
87
+ card.root.onclick = () => {
88
+ this.cardsFirst.forEach((c) => c.selected = false);
89
+ card.selected = true;
90
+ this.firstCard = card;
91
+ this.reset();
92
+ //onMonomerSelected(card.monomer);
93
+ };
94
+ monomerGalleryFirst.appendChild(card.root);
95
+ });
96
+
97
+ this.cardsSecond.forEach((card) => {
98
+ card.root.onclick = () => {
99
+ this.cardsSecond.forEach((c) => c.selected = false);
100
+ card.selected = true;
101
+ this.secondCard = card;
102
+ this.reset();
103
+ //onMonomerSelected(card.monomer);
104
+ };
105
+ monomerGallerySecond.appendChild(card.root);
106
+ });
107
+
108
+ this.cardsFirst[0].selected = true;
109
+ this.cardsSecond[0].selected = true;
110
+ this.firstCard = this.cardsFirst[0];
111
+ this.secondCard = this.cardsSecond[0];
112
+ this.root.appendChild(galleries);
113
+ } else {
114
+ const es = ui.divV(['Rule is active for all monomers, no examples to show']);
115
+ this.root.appendChild(es);
116
+ this.actionable = false;
117
+ }
118
+ }
119
+
120
+ async reset() {
121
+ if (this.actionable) {
122
+ const seqs: string[] = [
123
+ `${this.firstCard.monomer?.symbol}(${this.code})-A-A-A-A-${this.secondCard.monomer?.symbol}(${this.code})`
124
+ ];
125
+
126
+ const helmHelper = await getHelmHelper();
127
+ const [helms, isLinear, positionMaps] = doPolyToolConvert(seqs, this.rules, helmHelper);
128
+
129
+ const resHelmCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, 'helm', helms.length)
130
+ .init((rowIdx: number) => { return helms[rowIdx]; });
131
+ resHelmCol.semType = DG.SEMTYPE.MACROMOLECULE;
132
+ resHelmCol.meta.units = NOTATION.HELM;
133
+ resHelmCol.setTag(DG.TAGS.CELL_RENDERER, 'helm');
134
+
135
+ const rdKitModule: RDModule = await getRdKitModule();
136
+ const seqHelper: ISeqHelper = await getSeqHelper();
137
+
138
+ const lib = await getOverriddenLibrary(this.rules);
139
+ const resHelmColTemp = resHelmCol.temp;
140
+ resHelmCol.temp = resHelmColTemp;
141
+ const resMolCol = await helmToMol(resHelmCol, helms,
142
+ isLinear, true, false, false, lib, rdKitModule, seqHelper);
143
+
144
+ const mol = resMolCol.get(0);
145
+ const monomerMolSvg = mol && grok.chem.checkSmiles(mol) ?
146
+ grok.chem.drawMolecule(mol, 150, 120) :
147
+ grok.chem.drawMolecule(mol ?? '', 150, 120);
148
+
149
+ ui.empty(this.resulting);
150
+ this.resulting.append(ui.divH([monomerMolSvg], {style: {overflowX: 'auto', width: '100%', minHeight: '150px'}}));
151
+ }
152
+ }
153
+
154
+ render() {
155
+ if (this.actionable) {
156
+ this.cardsFirst.forEach((card) => card.render());
157
+ this.cardsSecond.forEach((card) => card.render());
158
+ }
159
+ }
160
+ }
@@ -1,7 +1,11 @@
1
1
  import * as DG from 'datagrok-api/dg';
2
2
  import * as grok from 'datagrok-api/grok';
3
+ import * as ui from 'datagrok-api/ui';
3
4
  import {ActiveFiles} from '@datagrok-libraries/utils/src/settings/active-files-base';
4
5
  import {RulesManager} from './rule-manager';
6
+ import {RuleCards} from './pt-rule-cards';
7
+ import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
8
+ import {applyNotationProviderForCyclized} from '../../package';
5
9
 
6
10
  export const RULES_PATH = 'System:AppData/SequenceTranslator/polytool-rules/';
7
11
  export const RULES_STORAGE_NAME = 'Polytool';
@@ -93,10 +97,22 @@ export class Rules {
93
97
  getLinkRulesDf(): DG.DataFrame {
94
98
  const length = this.linkRules.length;
95
99
  const codeCol = DG.Column.int(NAME_CODE, length);
100
+ codeCol.setTag('friendlyName', 'Code');
101
+ //ui.tooltip.bind(codeCol.root, 'Click to zoom');
96
102
  const firstMonomerCol = DG.Column.string(NAME_FIRST_MONOMERS, length);
103
+ firstMonomerCol.setTag('friendlyName', 'First monomers');
104
+ firstMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
105
+ applyNotationProviderForCyclized(firstMonomerCol, ',');
106
+
97
107
  const secondMonomerCol = DG.Column.string(NAME_SECOND_MONOMERS, length);
108
+ secondMonomerCol.setTag('friendlyName', 'Second monomers');
109
+ secondMonomerCol.semType = DG.SEMTYPE.MACROMOLECULE;
110
+ applyNotationProviderForCyclized(secondMonomerCol, ',');
111
+
98
112
  const firstLinkingGroup = DG.Column.int(NAME_FIRST_LINK, length);
113
+ firstLinkingGroup.setTag('friendlyName', 'First group');
99
114
  const secondLinkingGroup = DG.Column.int(NAME_SECOND_LINK, length);
115
+ secondLinkingGroup.setTag('friendlyName', 'Second group');
100
116
 
101
117
  for (let i = 0; i < length; i++) {
102
118
  codeCol.set(i, this.linkRules[i].code);
@@ -106,20 +122,43 @@ export class Rules {
106
122
  secondLinkingGroup.set(i, this.linkRules[i].secondLinkingGroup);
107
123
  }
108
124
 
109
- return DG.DataFrame.fromColumns([
125
+ const res = DG.DataFrame.fromColumns([
110
126
  codeCol, firstMonomerCol, secondMonomerCol, firstLinkingGroup, secondLinkingGroup
111
127
  ]);
128
+
129
+ return res;
130
+ }
131
+
132
+ async getLinkCards(): Promise<RuleCards[]> {
133
+ const length = this.linkRules.length;
134
+ const cards: RuleCards[] = new Array<RuleCards>(length);
135
+ const monomerLibHelper = await getMonomerLibHelper();
136
+ const systemMonomerLib = monomerLibHelper.getMonomerLib();
137
+
138
+ for (let i = 0; i < length; i++) {
139
+ cards[i] = new RuleCards(this.linkRules[i].firstMonomers, this.linkRules[i].secondMonomers,
140
+ systemMonomerLib, this.linkRules[i].code, this);
141
+ }
142
+
143
+ return cards;
112
144
  }
113
145
 
114
146
  getSynthesisRulesDf(): DG.DataFrame {
115
147
  const length = this.reactionRules.length;
116
148
  const codeCol = DG.Column.int(NAME_CODE, length);
149
+ codeCol.setTag('friendlyName', 'Code');
117
150
  const firstMonomerCol = DG.Column.string(NAME_FIRST_MONOMERS, length);
151
+ firstMonomerCol.setTag('friendlyName', 'First monomers');
118
152
  const secondMonomerCol = DG.Column.string(NAME_SECOND_MONOMERS, length);
153
+ secondMonomerCol.setTag('friendlyName', 'Second monomers');
119
154
  const name = DG.Column.string(NAME_REACTION_NAME, length);
155
+ name.setTag('friendlyName', 'Name');
120
156
  const firstReactant = DG.Column.string('firstReactant', length);
157
+ firstReactant.setTag('friendlyName', 'First reactant');
121
158
  const secondReactant = DG.Column.string('secondReactant', length);
159
+ secondReactant.setTag('friendlyName', 'Second reactant');
122
160
  const product = DG.Column.string('product', length);
161
+ product.setTag('friendlyName', 'Product');
123
162
 
124
163
  for (let i = 0; i < length; i++) {
125
164
  codeCol.set(i, this.reactionRules[i].code);
@@ -121,9 +121,10 @@ export function fromObjectsToHelm(linkages: Linkage[], monomers: string[][]): st
121
121
  return helm;
122
122
  }
123
123
 
124
- //homo and hetero dimers
125
- export function handleDuplicated(sequence: string, rules: Rules): [Linkage[], string[]] {
124
+ //homo and hetero dimers/ also fills map from initial positions to positions arrays
125
+ export function handleDuplicated(sequence: string, rules: Rules): [Linkage[], string[], boolean[]] {
126
126
  const mainFragments: string[] = [];
127
+ const isDuplicated: boolean[] = [];
127
128
  const linkages: Linkage[] = [];
128
129
  const heterodimerCode = rules.heterodimerCode;
129
130
  const homodimerCode = rules.homodimerCode;
@@ -134,8 +135,11 @@ export function handleDuplicated(sequence: string, rules: Rules): [Linkage[], st
134
135
  linkages.push({fChain: 0, sChain: 1, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
135
136
  mainFragments.push(heterodimeric[1].replaceAll('{', '').replaceAll('}', ''));
136
137
  mainFragments.push(heterodimeric[2].replaceAll('{', '').replaceAll('}', ''));
138
+ isDuplicated.push(false);
139
+ isDuplicated.push(false);
137
140
  } else {
138
141
  mainFragments.push(sequence);
142
+ isDuplicated.push(false);
139
143
  }
140
144
 
141
145
  //NOTICE: this works only with simple single dimers
@@ -151,30 +155,16 @@ export function handleDuplicated(sequence: string, rules: Rules): [Linkage[], st
151
155
 
152
156
  mainFragments[i] = linker + body;
153
157
  mainFragments.push(body);
158
+ isDuplicated.push(true);
154
159
  }
155
160
  }
156
161
 
157
- for (let i = 0; i < mainFragments.length; i++) {
158
- if (homodimerCode !== null && mainFragments[i].includes(`(${homodimerCode!})`)) {
159
- const idxSequence = mainFragments.length;
160
-
161
- linkages.push({fChain: i, sChain: idxSequence, fMonomer: 1, sMonomer: 1, fR: 1, sR: 1});
162
- const rawDimer = mainFragments[i].replace(`(${homodimerCode!})`, '');
163
- const idx = rawDimer.indexOf('{');
164
- const linker = rawDimer.slice(0, idx);
165
- const body = rawDimer.replace(linker, '').replaceAll('{', '').replaceAll('}', '');
166
-
167
- mainFragments[i] = linker + body;
168
- mainFragments.push(body);
169
- }
170
- }
171
-
172
- return [linkages, mainFragments];
162
+ return [linkages, mainFragments, isDuplicated];
173
163
  }
174
164
 
175
- export function handleLinkRules(mf: string[], monomers: string[][], linkages: Linkage[], rules: Rules): void {
176
- for (let i = 0; i < mf.length; i++) {
177
- const rawMonomers = mf[i].split('-');
165
+ export function handleLinkRules(monomers: string[][], linkages: Linkage[], rules: Rules): void {
166
+ for (let i = 0; i < monomers.length; i++) {
167
+ const rawMonomers = monomers[i];
178
168
  const linkedPositions = getLinkedPositions(rawMonomers, rules.linkRules);
179
169
  const [allPos1, allPos2, allAttaches1, allAttaches2] =
180
170
  getAllCycles(rules.linkRules, rawMonomers, linkedPositions);