@datagrok/sequence-translator 1.4.10 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,206 @@
1
+ import * as DG from 'datagrok-api/dg';
2
+ import * as grok from 'datagrok-api/grok';
3
+ import {getMonomerPairs, getRules, Rules} from './pt-rules';
4
+ import {_package, applyNotationProviderForCyclized} from '../../package';
5
+ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
6
+ import {doPolyToolConvert} from './pt-conversion';
7
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
8
+
9
+ export class RulesManager {
10
+ rules: Rules;
11
+ linkRuleDataFrame: DG.DataFrame;
12
+ synthRuleDataFrame: DG.DataFrame;
13
+ fileName: string;
14
+ v: DG.View | null = null;
15
+
16
+ homoDimerInput: DG.InputBase;
17
+ heteroDimerInput: DG.InputBase;
18
+
19
+ currentTab = '';
20
+
21
+ private static instance: RulesManager;
22
+
23
+ protected constructor(rules: Rules, fileName: string) {
24
+ this.rules = rules;
25
+ this.linkRuleDataFrame = this.rules.getLinkRulesDf();
26
+ this.synthRuleDataFrame = this.rules.getSynthesisRulesDf();
27
+ this.fileName = fileName;
28
+
29
+ const homoValue = this.rules.homodimerCode ? this.rules.homodimerCode : '';
30
+ const heteroValue = this.rules.heterodimerCode ? this.rules.heterodimerCode : '';
31
+ this.homoDimerInput = ui.input.string('Homo dimer', {value: homoValue, onValueChanged: () => {}, nullable: false});
32
+ this.heteroDimerInput = ui.input.string(
33
+ 'Hetero dimer', {value: heteroValue, onValueChanged: () => {}, nullable: false}
34
+ );
35
+ }
36
+
37
+ async getView(): Promise<DG.ViewBase> {
38
+ if (!this.v) {
39
+ this.v = DG.View.create();
40
+ this.v.name = 'Manage Polytool Rules';
41
+ this.v.append(await this.getForm());
42
+ }
43
+
44
+ return this.v;
45
+ }
46
+
47
+ public static async getInstance(name: string): Promise<RulesManager> {
48
+ if (!this.instance) {
49
+ const rules = await getRules([name]);
50
+ this.instance = new RulesManager(rules, name);
51
+ }
52
+ return this.instance;
53
+ }
54
+
55
+ save(): void {
56
+ this.rules.homodimerCode = this.homoDimerInput.value;
57
+ this.rules.heterodimerCode = this.heteroDimerInput.value;
58
+ this.rules.setLinkRules(this.linkRuleDataFrame);
59
+ this.rules.setSynthesisRules(this.synthRuleDataFrame);
60
+
61
+ const saveable = {
62
+ homodimerCode: this.rules.homodimerCode,
63
+ heterodimerCode: this.rules.heterodimerCode,
64
+ linkRules: this.rules.linkRules,
65
+ reactionRules: this.rules.reactionRules,
66
+ };
67
+
68
+ const rrrr = JSON.stringify(saveable, undefined, 2);
69
+ _package.files.writeAsText(`polytool-rules/${this.fileName}`, rrrr);
70
+ grok.shell.info(`Polytool rules at ${this.fileName} was updated`);
71
+ }
72
+
73
+ private createGridDiv(name: string, grid: DG.Grid) {
74
+ const header = ui.h1(name, 'polytool-grid-header');
75
+ grid.root.prepend(header);
76
+ grid.root.style.height = '100%';
77
+ return grid.root;
78
+ };
79
+
80
+ async getLinkExamplesGrid() {
81
+ const seqs: string[] = [];
82
+
83
+ for (let i = 0; i < this.rules.linkRules.length; i++) {
84
+ const code = this.rules.linkRules[i].code;
85
+ const [firstMonomers, secondMonomers] = getMonomerPairs(this.rules.linkRules[i]);
86
+ for (let j = 0; j < firstMonomers.length; j++) {
87
+ const seq = `${firstMonomers[j]}(${code})-A-A-A-A-${secondMonomers[j]}(${code})-A`;
88
+ seqs.push(seq);
89
+ }
90
+ }
91
+ const helmHelper = await getHelmHelper();
92
+
93
+ const helms = doPolyToolConvert(seqs, this.rules, helmHelper);
94
+
95
+ const initCol = DG.Column.fromStrings('monomers', seqs);
96
+ const helmCol = DG.Column.fromStrings('helm', helms);
97
+
98
+ applyNotationProviderForCyclized(initCol, '-');
99
+ initCol.semType = DG.SEMTYPE.MACROMOLECULE;
100
+
101
+ helmCol.semType = DG.SEMTYPE.MACROMOLECULE;
102
+ helmCol.meta.units = NOTATION.HELM;
103
+ helmCol.setTag(DG.TAGS.CELL_RENDERER, 'helm');
104
+ return DG.DataFrame.fromColumns([
105
+ initCol, helmCol
106
+ ]).plot.grid();
107
+ }
108
+
109
+ async getReactionExamplesGrid() {
110
+ const seqs: string[] = [];
111
+
112
+ for (let i = 0; i < this.rules.reactionRules.length; i++) {
113
+ const code = this.rules.reactionRules[i].code;
114
+ const [firstMonomers, secondMonomers] = getMonomerPairs(this.rules.reactionRules[i]);
115
+ for (let j = 0; j < firstMonomers.length; j++) {
116
+ const seq = `${firstMonomers[j]}(${code})-A-A-A-A-${secondMonomers[j]}(${code})`;
117
+ seqs.push(seq);
118
+ }
119
+ }
120
+ const helmHelper = await getHelmHelper();
121
+
122
+ const helms = doPolyToolConvert(seqs, this.rules, helmHelper);
123
+
124
+ const initCol = DG.Column.fromStrings('monomers', seqs);
125
+ const helmCol = DG.Column.fromStrings('helm', helms);
126
+
127
+ initCol.semType = DG.SEMTYPE.MACROMOLECULE;
128
+ applyNotationProviderForCyclized(initCol, '-');
129
+
130
+ helmCol.semType = DG.SEMTYPE.MACROMOLECULE;
131
+ helmCol.meta.units = NOTATION.HELM;
132
+ helmCol.setTag(DG.TAGS.CELL_RENDERER, 'helm');
133
+ return DG.DataFrame.fromColumns([
134
+ initCol, helmCol
135
+ ]).plot.grid();
136
+ }
137
+
138
+ async getForm() {
139
+ inputsTabControl: DG.TabControl;
140
+
141
+ const dimerInputsDiv = ui.divV([
142
+ this.homoDimerInput,
143
+ this.heteroDimerInput,
144
+ ]);
145
+
146
+ const linkExamples = await this.getLinkExamplesGrid();
147
+ const reactionExamples = await this.getReactionExamplesGrid();
148
+
149
+ const inputsTabControl = ui.tabControl({
150
+ 'Links': linkExamples,
151
+ 'Reactions': reactionExamples,
152
+ 'Dimers': dimerInputsDiv,
153
+ }, false);
154
+
155
+ inputsTabControl.root.style.height = '90%';
156
+ inputsTabControl.root.style.width = '100%';
157
+ inputsTabControl.root.classList.add('rules-manager-form-tab-control');
158
+ inputsTabControl.header.style.marginBottom = '10px';
159
+
160
+ const linksGridDiv = this.createGridDiv('Link rules', this.linkRuleDataFrame.plot.grid({showAddNewRowIcon: true}));
161
+ const reactionsGridDiv =
162
+ this.createGridDiv('Reaction rules', this.synthRuleDataFrame.plot.grid({showAddNewRowIcon: true}));
163
+
164
+ linksGridDiv.style.width = '100%';
165
+ reactionsGridDiv.style.width = '100%';
166
+
167
+ const divs = [linksGridDiv, reactionsGridDiv, ui.div()];
168
+ divs[0].style.removeProperty('display');
169
+ divs[1].style.display = 'none';
170
+ divs[2].style.display = 'none';
171
+
172
+ inputsTabControl.onTabChanged.subscribe(() => {
173
+ this.currentTab = inputsTabControl.currentPane.name;
174
+
175
+ const idx = inputsTabControl.panes.findIndex((p) => p.name == this.currentTab);
176
+
177
+ for (let i = 0; i < divs.length; i++) {
178
+ if (i == idx)
179
+ divs[i].style.removeProperty('display');
180
+ else
181
+ divs[i].style.display = 'none';
182
+ }
183
+ });
184
+
185
+ const saveButton = ui.bigButton('Save changes', () => {
186
+ this.save();
187
+ });
188
+
189
+
190
+ const panel = ui.divV([
191
+ inputsTabControl.root,
192
+ saveButton
193
+ ]);
194
+
195
+ panel.style.height = '100%';
196
+ panel.style.alignItems = 'center';
197
+
198
+ const form = ui.splitH([
199
+ panel,
200
+ ui.divV(divs, {style: {width: '100%'}})
201
+ ], {style: {width: '100%'}}, true);
202
+ form.style.height = '100%';
203
+ return form;
204
+ }
205
+ }
206
+
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
4
4
  import {_package} from '../package';
5
5
  import {defaultErrorHandler} from '../utils/err-info';
6
6
  import {PT_UI_DIALOG_CONVERSION, PT_UI_RULES_USED} from './const';
7
- import {RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
7
+ import {RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './conversion/pt-rules';
8
8
 
9
9
  /** Inputs of polyToolConvert2 package function */
10
10
  export enum P {
@@ -14,7 +14,7 @@ import {addMonomerHoverLink, buildMonomerHoverLink} from '@datagrok-libraries/bi
14
14
  import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
15
15
  import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
16
16
 
17
- import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
17
+ import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './conversion/pt-rules';
18
18
  import {doPolyToolConvert} from './conversion/pt-conversion';
19
19
  import {getOverriddenLibrary} from './conversion/pt-misc';
20
20
  import {defaultErrorHandler} from '../utils/err-info';
@@ -26,7 +26,7 @@ import {defaultErrorHandler} from '../utils/err-info';
26
26
  import {PolyToolPlaceholdersBreadthInput} from './pt-placeholders-breadth-input';
27
27
  import {PT_UI_DIALOG_ENUMERATION, PT_UI_GET_HELM, PT_UI_HIGHLIGHT_MONOMERS, PT_UI_RULES_USED, PT_UI_USE_CHIRALITY} from './const';
28
28
  import {PolyToolDataRole, PolyToolTags} from '../consts';
29
- import {RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
29
+ import {RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './conversion/pt-rules';
30
30
  import {Chain} from './conversion/pt-chain';
31
31
  import {polyToolConvert} from './pt-dialog';
32
32
 
@@ -627,9 +627,9 @@ async function polyToolEnumerateSeq(
627
627
  }
628
628
  const enumeratorResDf = DG.DataFrame.fromColumns([enumCol]);
629
629
  await grok.data.detectSemanticTypes(enumeratorResDf);
630
- if (dataRole == PolyToolDataRole.template) {
630
+ if (dataRole == PolyToolDataRole.template)
631
631
  applyNotationProviderForCyclized(enumCol, '-');
632
- }
632
+
633
633
 
634
634
  if (toAtomicLevel) {
635
635
  let resHelmCol: DG.Column<string>;
@@ -10,7 +10,7 @@ import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
10
10
 
11
11
  import {defaultErrorHandler} from '../utils/err-info';
12
12
  import {doPolyToolUnrule} from './pt-unrule';
13
- import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
13
+ import {getRules, RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './conversion/pt-rules';
14
14
  import {PT_ERROR_DATAFRAME, PT_UI_DIALOG_UNRULE, PT_UI_RULES_USED} from './const';
15
15
 
16
16
  import {_package} from '../package';
@@ -6,7 +6,7 @@ import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
6
6
 
7
7
  import {Chain} from './conversion/pt-chain';
8
8
  import {getPolyToolUnruleDialog} from './pt-unrule-dialog';
9
- import {Rules} from './pt-rules';
9
+ import {Rules} from './conversion/pt-rules';
10
10
 
11
11
  import {_package} from '../package';
12
12
  import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
@@ -4,7 +4,7 @@ import * as DG from 'datagrok-api/dg';
4
4
 
5
5
  import {before, after, category, expect, test, expectArray, testEvent, delay} from '@datagrok-libraries/utils/src/test';
6
6
  import {Chain} from '../polytool/conversion/pt-chain';
7
- import {getRules} from '../polytool/pt-rules';
7
+ import {getRules} from '../polytool/conversion/pt-rules';
8
8
  import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
9
9
 
10
10
  category('PolyTool: Chain', () => {
@@ -54,15 +54,11 @@ category('PolyTool: Chain', () => {
54
54
  templateHelm: 'PEPTIDE1{[(#3)Succ]}' + '|' +
55
55
  'PEPTIDE2{[A(CHOL)].F.[C(1)].T.G.H.Y.P.[C(1)].[NH2]}' + '$' +
56
56
  'PEPTIDE1,PEPTIDE2,1:R1-1:R1' + '$$$' + 'V2.0',
57
- mmHelm: 'PEPTIDE1{[Succ].[A(CHOL)].F.C.T.G.H.Y.P.C.[NH2]}' + '|' +
58
- 'PEPTIDE2{[A(CHOL)].F.C.T.G.H.Y.P.C.[NH2]}' + '$' +
59
- 'PEPTIDE1,PEPTIDE2,1:R1-1:R1' + '|' +
60
- 'PEPTIDE1,PEPTIDE1,4:R3-10:R3' + '|' +
61
- 'PEPTIDE2,PEPTIDE2,3:R3-9:R3' + '$$$V2.0',
57
+ mmHelm: 'PEPTIDE1{[(#3)Succ].[{A(CHOL)].F.C.T.G.H.Y.P.C.[NH2}]}$PEPTIDE1,PEPTIDE1,4:R3-10:R3$$$V2.0',
62
58
  },
63
59
  tgt: {
64
60
  templateChain: {monomerCount: [1, 10], linkageCount: 1},
65
- mmChain: {monomerCount: [11, 10], linkageCount: 3,}
61
+ mmChain: {monomerCount: [11], linkageCount: 1}
66
62
  }
67
63
  },
68
64
  'dimerized2': {
@@ -72,15 +68,11 @@ category('PolyTool: Chain', () => {
72
68
  'PEPTIDE2{R.F.[C(1)].T.G.H.F.P.[C(1)].[NH2]}' + '|' +
73
69
  'PEPTIDE3{[($3)A(CHOL)].F.[C(1)].Y.H.G.D.N.[C(1)].[meI]}' + '$' +
74
70
  'PEPTIDE1,PEPTIDE2,1:R1-1:R1' + '$$$' + 'V2.0',
75
- mmHelm: 'PEPTIDE1{[Succ].R.F.C.T.G.H.F.P.C.[NH2]}' + '|' +
76
- 'PEPTIDE2{[A(CHOL)].F.C.Y.H.G.D.N.C.[meI]}' + '$' +
77
- 'PEPTIDE1,PEPTIDE2,1:R1-1:R1' + '|' +
78
- 'PEPTIDE1,PEPTIDE1,4:R3-10:R3' + '|' +
79
- 'PEPTIDE2,PEPTIDE2,3:R3-9:R3' + '$$$V2.0',
71
+ mmHelm: 'PEPTIDE1{[($3)Succ].[{R].F.C.T.G.H.F.P.C.[NH2}($3){A(CHOL)].F.[C(1)].Y.H.G.D.N.[C(1)].[meI}]}$PEPTIDE1,PEPTIDE1,4:R3-10:R3$$$V2.0',
80
72
  },
81
73
  tgt: {
82
- templateChain: {monomerCount: [1, 10, 10], linkageCount: 1,},
83
- mmChain: {monomerCount: [11, 10], linkageCount: 3,}
74
+ templateChain: {monomerCount: [1, 10, 10], linkageCount: 1},
75
+ mmChain: {monomerCount: [20], linkageCount: 1}
84
76
  }
85
77
  }
86
78
  };
@@ -5,7 +5,7 @@ import * as DG from 'datagrok-api/dg';
5
5
  import {before, after, category, expect, test, expectArray, testEvent, delay} from '@datagrok-libraries/utils/src/test';
6
6
  import {Chain} from '../polytool/conversion/pt-chain';
7
7
  import {getInnerIdx, getOuterIdx} from '../polytool/conversion/pt-misc';
8
- import {getRules} from '../polytool/pt-rules';
8
+ import {getRules} from '../polytool/conversion/pt-rules';
9
9
  import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
10
10
 
11
11
  category('PolyTool: Chain: parseNotation', () => {
@@ -2,7 +2,8 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
- import {before, after, category, expect, test, expectArray, testEvent, delay, expectObject} from '@datagrok-libraries/utils/src/test';
5
+ import {before, after, category, expect, test, expectArray, testEvent, expectObject}
6
+ from '@datagrok-libraries/utils/src/test';
6
7
  import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
7
8
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
8
9
  import {
@@ -16,7 +17,7 @@ import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-
16
17
 
17
18
  import {doPolyToolConvert} from '../polytool/conversion/pt-conversion';
18
19
  import {getOverriddenLibrary} from '../polytool/conversion/pt-misc';
19
- import {getRules} from '../polytool/pt-rules';
20
+ import {getRules} from '../polytool/conversion/pt-rules';
20
21
 
21
22
 
22
23
  import {_package} from '../package-test';
@@ -5,6 +5,6 @@ import * as DG from 'datagrok-api/dg';
5
5
  import {before, after, category, expect, test, expectArray, testEvent, delay} from '@datagrok-libraries/utils/src/test';
6
6
 
7
7
  import {doPolyToolUnrule} from '../polytool/pt-unrule';
8
- import {getRules} from '../polytool/pt-rules';
8
+ import {getRules} from '../polytool/conversion/pt-rules';
9
9
 
10
10
  import {_package} from '../package-test';
@@ -15,8 +15,8 @@ import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
15
15
  import {RDModule} from '@datagrok-libraries/chem-meta/src/rdkit-api';
16
16
 
17
17
  import {_package} from '../package-test';
18
- import {getNewMonomer} from '../polytool/conversion/pt-misc';
19
- import {getRules, RuleReaction} from '../polytool/pt-rules';
18
+ import {getNewMonomers} from '../polytool/conversion/pt-misc';
19
+ import {getRules, RuleReaction} from '../polytool/conversion/pt-rules';
20
20
 
21
21
  category('toAtomicLevel', () => {
22
22
  let userLibSettings: UserLibSettings;
@@ -78,10 +78,10 @@ category('toAtomicLevel', () => {
78
78
  const rules = await getRules(['rules_example.json']);
79
79
  const reactionRule = rules.reactionRules.find((r) => r.name == 'GGaz')!;
80
80
 
81
- const [newSymbol, newMonomer] = getNewMonomer(rdKitModule, systemMonomerLib, reactionRule);
82
- expect(newSymbol, reactionRule.name);
81
+ const [newSymbols, newMonomers] = getNewMonomers(rdKitModule, systemMonomerLib, reactionRule);
82
+ expect(newSymbols[0], reactionRule.name);
83
83
 
84
- const mol = rdKitModule.get_mol(newMonomer.molfile);
84
+ const mol = rdKitModule.get_mol(newMonomers[0].molfile);
85
85
  try {
86
86
  const molInchi = mol.get_inchi();
87
87
  const molInchiKey = rdKitModule.get_inchikey_for_inchi(molInchi);
@@ -1,93 +0,0 @@
1
- import * as DG from 'datagrok-api/dg';
2
- import * as grok from 'datagrok-api/grok';
3
- import {ActiveFiles} from '@datagrok-libraries/utils/src/settings/active-files-base';
4
-
5
- export const RULES_PATH = 'System:AppData/SequenceTranslator/polytool-rules/';
6
- export const RULES_STORAGE_NAME = 'Polytool';
7
- export const RULES_TYPE_LINK = 'link';
8
- export const RULES_TYPE_REACTION = 'reaction';
9
- export const RULES_TYPE_HOMODIMER = 'fragmentDuplication';
10
- export const RULES_TYPE_HETERODIMER = 'differentFragments';
11
-
12
- export class RuleInputs extends ActiveFiles {
13
- constructor(
14
- path: string, userStorageName: string, ext: string,
15
- options?: { onValueChanged: (value: string[]) => void }
16
- ) {
17
- super(path, userStorageName, ext, options);
18
- }
19
- }
20
-
21
- export type Rules = {
22
- homodimerCode: string | null,
23
- heterodimerCode: string | null,
24
- linkRules: RuleLink[],
25
- reactionRules: RuleReaction[]
26
- }
27
-
28
- export type RuleLink = {
29
- code: number,
30
- firstMonomer: string,
31
- secondMonomer: string,
32
- firstSubstitution: string,
33
- secondSubstitution: string,
34
- firstLinkingGroup: number,
35
- secondLinkingGroup: number
36
- }
37
-
38
- export type RuleReaction = {
39
- code: number,
40
- firstMonomer: string,
41
- secondMonomer: string,
42
- reaction: string,
43
- name: string
44
- }
45
-
46
- export async function getRules(ruleFiles: string[]): Promise<Rules> {
47
- const fileSource = new DG.FileSource(RULES_PATH);
48
- const linkRules: RuleLink[] = [];
49
- const reactionRules: RuleReaction[] = [];
50
- const rules: Rules = {homodimerCode: null, heterodimerCode: null, linkRules: linkRules, reactionRules: reactionRules};
51
-
52
- for (let i = 0; i < ruleFiles.length; i++) {
53
- const rulesRaw = await fileSource.readAsText(ruleFiles[i].replace(RULES_PATH, ''));
54
- const ruleSingle = JSON.parse(rulesRaw);
55
- for (let j = 0; j < ruleSingle.length; j++) {
56
- if (ruleSingle[j].type !== undefined && ruleSingle[j].code !== undefined) {
57
- switch (ruleSingle[j].type) {
58
- case RULES_TYPE_LINK: {
59
- const rule = ruleSingle[j].monomericSubstitution;
60
- rule['code'] = ruleSingle[j].code;
61
- linkRules.push(rule);
62
- break;
63
- }
64
- case RULES_TYPE_REACTION: {
65
- const rule = ruleSingle[j].monomericSubstitution;
66
- rule['code'] = ruleSingle[j].code;
67
- reactionRules.push(rule);
68
- break;
69
- }
70
- case RULES_TYPE_HOMODIMER: {
71
- if (rules.homodimerCode)
72
- grok.shell.warning(`PolyTool: homodimer code is duplicated in rules.`);
73
- rules.homodimerCode = ruleSingle[j].code;
74
- break;
75
- }
76
- case RULES_TYPE_HETERODIMER: {
77
- if (rules.heterodimerCode)
78
- grok.shell.warning(`PolyTool: heterodimer code is duplicated in rules.`);
79
- rules.heterodimerCode = ruleSingle[j].code;
80
- break;
81
- }
82
- default:
83
- grok.shell.warning(`PolyTool: Unexpected type - '${ruleSingle[j]}'.`);
84
- break;
85
- }
86
- } else {
87
- grok.shell.warning('Polytool: rules contain invalid rule');
88
- }
89
- }
90
- }
91
-
92
- return rules;
93
- }