@datagrok/sequence-translator 1.5.3 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,8 @@
1
1
 
2
2
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
3
3
  import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
4
-
5
4
  import {Rules} from './pt-rules';
6
5
  import {Chain} from './pt-chain';
7
-
8
6
  import {_package} from '../../package';
9
7
 
10
8
  /** The main PolyTool convert engine. Returns list of Helms. Covered with tests. */
@@ -13,7 +11,8 @@ export function doPolyToolConvert(sequences: string[], rules: Rules, helmHelper:
13
11
  for (let i = 0; i < sequences.length; i++) {
14
12
  try {
15
13
  if (sequences[i] == null) { helms[i] = ''; } else {
16
- const chain = Chain.fromNotation(sequences[i], rules, helmHelper);
14
+ const chain = Chain.fromSeparator(sequences[i], helmHelper);
15
+ chain.applyRules(rules);
17
16
  helms[i] = chain.getHelm();
18
17
  }
19
18
  } catch (err: any) {
@@ -1,16 +1,11 @@
1
- import * as grok from 'datagrok-api/grok';
2
-
3
- import wu from 'wu';
4
- import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
5
- import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
6
- import {IMonomerLib, IMonomerLibBase, Monomer, MonomerLibData, RGroup} from '@datagrok-libraries/bio/src/types';
7
- import {RDModule, RDMol, RDReaction, MolList, RDReactionResult} from '@datagrok-libraries/chem-meta/src/rdkit-api';
8
- import {HELM_REQUIRED_FIELD as REQ,
9
- HELM_OPTIONAL_FIELDS as OPT, HELM_RGROUP_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
10
- import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
11
- import {Rules, RuleReaction, getMonomerPairs} from './pt-rules';
12
- import {InvalidReactionError, MonomerNotFoundError} from '../types';
13
- import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
1
+ export type Linkage = {
2
+ fChain: number,
3
+ sChain: number,
4
+ /** Continuous 1-based numbering */ fMonomer: number,
5
+ /** Continuous 1-based numbering */ sMonomer: number,
6
+ fR: number,
7
+ sR: number
8
+ }
14
9
 
15
10
  /** Gets 0-based in-index (simple polymer) of out-index (continuous) {@link idx} */
16
11
  export function getInnerIdx(outIdx: number, monomers: string[][]): [number, number] {
@@ -32,172 +27,3 @@ export function getOuterIdx(inIdx: number, spIdx: number, monomers: string[][]):
32
27
  outIdx += monomers[i].length;
33
28
  return outIdx + inIdx;
34
29
  }
35
-
36
- function getMonomersMolBlocks(monomer1: Monomer, monomer2: Monomer): [string, string] {
37
- const mb1 = monomer1.molfile;
38
- let mb2 = monomer2.molfile;
39
- const addGroups = monomer1.rgroups.length;
40
-
41
- //mol v2000 monomer
42
- const rgpIdx = mb2.indexOf('M RGP');
43
- if (rgpIdx !== -1) {
44
- const groupsCountStr = mb2.substring(rgpIdx + 6, rgpIdx + 9);
45
- const groupsCount = Number(groupsCountStr);
46
-
47
- for (let i = 0; i < groupsCount; i++) {
48
- const start = rgpIdx + 9 + 4 + i * 8;
49
- const end = rgpIdx + 9 + 8 + i * 8;
50
- const rGroupSpecifier = mb2.substring(start, end);
51
- const groupPosition = Number(rGroupSpecifier) + addGroups;
52
- const digits = Math.floor(Math.log10(groupPosition) + 1);
53
- const newSpecifier = ' '.repeat(4 - digits) + String(groupPosition);
54
- mb2 = mb2.substring(0, start) + newSpecifier + mb2.substring(end, mb2.length);
55
- }
56
- }
57
-
58
- //TODO: same for v3000 monomer
59
-
60
- return [mb1, mb2];
61
- }
62
-
63
- function getSyntheticMolBlock(rdkit: RDModule, reaction: string,
64
- mb1: string, mb2: string, monomerName: string): string {
65
- let rxn: RDReaction | null = null;
66
- let mols: MolList | null = null;
67
- let mol1: RDMol | null = null;
68
- let mol2: RDMol | null = null;
69
- let rctns: RDReactionResult | null = null;
70
- let molP: RDMol | null = null;
71
- let molBlock = '';
72
-
73
- try {
74
- rxn = rdkit.get_rxn(reaction);
75
- if (!rxn) throw new InvalidReactionError(reaction);
76
- mols = new rdkit.MolList();
77
- mol1 = rdkit.get_mol(mb1!);
78
- mol2 = rdkit.get_mol(mb2!);
79
- mols.append(mol1!);
80
- mols.append(mol2!);
81
-
82
- rctns = rxn.run_reactants(mols, 1);
83
- //const size = rctns.size();
84
- const element = rctns.get(0);
85
-
86
- molP = element.next();
87
- molBlock = molP?.get_molblock();//molP?.get_v3Kmolblock();//
88
- } catch (err: any) {
89
- const [errMsg, _errStack] = errInfo(err);
90
- grok.shell.error(`Can not assemble monomer '${monomerName}': ${errMsg}.`);
91
- throw err;
92
- } finally {
93
- rxn?.delete();
94
- mols?.delete();
95
- mol1?.delete();
96
- mol2?.delete();
97
- rctns?.delete();
98
- molP?.delete();
99
- }
100
-
101
- return molBlock;
102
- }
103
-
104
- function getNewGroups(monomer1: Monomer, monomer2: Monomer): RGroup[] {
105
- const groups = new Array<RGroup>(monomer1?.rgroups.length! + monomer2?.rgroups.length!);
106
- const length1 = monomer1?.rgroups.length!;
107
- const length2 = monomer2?.rgroups.length!;
108
-
109
- for (let i = 0; i < length1; i++)
110
- groups[i] = monomer1?.rgroups[i]!;
111
-
112
- for (let i = 0; i < length2; i++) {
113
- const rGroupSpecifier = monomer2?.rgroups[i]!.label.replace('R', '');
114
- const groupPosition = Number(rGroupSpecifier) + length1;
115
- const group: RGroup = {
116
- //@ts-ignore
117
- [HELM_RGROUP_FIELDS.CAP_GROUP_SMILES_UPPERCASE]: monomer2?.rgroups[i].capGroupSMILES
118
- .replace(rGroupSpecifier, String(groupPosition)),
119
- [HELM_RGROUP_FIELDS.ALTERNATE_ID]: monomer2?.rgroups[i].alternateId
120
- .replace(rGroupSpecifier, String(groupPosition)),
121
- [HELM_RGROUP_FIELDS.CAP_GROUP_NAME]: monomer2?.rgroups[i].capGroupName,
122
- [HELM_RGROUP_FIELDS.LABEL]: monomer2?.rgroups[i].label.replace(rGroupSpecifier, String(groupPosition)),
123
- };
124
-
125
- groups[i + length1] = group;
126
- }
127
-
128
- return groups;
129
- }
130
-
131
- export function getNewMonomers(rdkit: RDModule, mLib: IMonomerLib, rule: RuleReaction): [string[], Monomer[]] {
132
- const reacSmarts = rule.reaction;
133
- const monomerName = rule.name;
134
-
135
- const [firstMonomers, secondMonomers] = getMonomerPairs(rule);
136
-
137
- const monomerNames = new Array<string>(firstMonomers.length);
138
- const resMonomers = new Array<Monomer>(firstMonomers.length);
139
-
140
- for (let i = 0; i < firstMonomers.length; i ++) {
141
- const monomer1 = mLib.getMonomer('PEPTIDE', firstMonomers[i]);
142
- if (!monomer1) throw new MonomerNotFoundError('PEPTIDE', firstMonomers[i]);
143
- const monomer2 = mLib.getMonomer('PEPTIDE', secondMonomers[i]);
144
- if (!monomer2) throw new MonomerNotFoundError('PEPTIDE', secondMonomers[i]);
145
-
146
- const [mb1, mb2] = getMonomersMolBlocks(monomer1!, monomer2!);
147
- const molBlock = getSyntheticMolBlock(rdkit, reacSmarts, mb1, mb2, monomerName);
148
- const groups: RGroup[] = getNewGroups(monomer1!, monomer2!);
149
-
150
- const resMonomer: Monomer = {
151
- [REQ.SYMBOL]: monomerName,
152
- [REQ.NAME]: monomerName,
153
- [REQ.MOLFILE]: molBlock,
154
- [REQ.AUTHOR]: '',
155
- [REQ.ID]: 0,
156
- [REQ.RGROUPS]: groups,
157
- [REQ.SMILES]: '',
158
- [REQ.POLYMER_TYPE]: 'PEPTIDE',
159
- [REQ.MONOMER_TYPE]: 'Backbone',
160
- [REQ.CREATE_DATE]: null,
161
- // // @ts-ignore
162
- // lib: {source: 'Reaction'},
163
- };
164
-
165
- resMonomer[OPT.META] = Object.assign(resMonomer[OPT.META] ?? {},
166
- {'colors': {'default': {line: '#2083D5', text: '#2083D5', background: '#F2F2F5'}}});
167
-
168
- monomerNames[i] = monomerName;
169
- resMonomers[i] = resMonomer;
170
- }
171
-
172
- return [monomerNames, resMonomers];
173
- }
174
-
175
- export async function getOverriddenLibrary(rules: Rules): Promise<IMonomerLibBase> {
176
- const monomerLibHelper = await getMonomerLibHelper();
177
- const systemMonomerLib = monomerLibHelper.getMonomerLib();
178
-
179
- const rdkit = await getRdKitModule();
180
- const argLib: { [symbol: string]: Monomer } = {};
181
-
182
- let names: string [] = [];
183
- let monomers: Monomer [] = [];
184
-
185
- for (let i = 0; i < rules.reactionRules.length; i++) {
186
- try {
187
- [names, monomers] = getNewMonomers(rdkit, systemMonomerLib, rules.reactionRules[i]);
188
- } catch (e: any) {
189
- names = [];
190
- monomers = [];
191
- console.error(e);
192
- } finally {
193
- for (let j = 0; j < names.length; j ++)
194
- argLib[names[j]] = monomers[j];
195
- }
196
- }
197
-
198
- const overrideMonomerLibData: MonomerLibData = {[PolymerTypes.PEPTIDE]: argLib};
199
- const overriddenMonomerLib = systemMonomerLib.override(overrideMonomerLibData,
200
- 'ST-PT-reactions.' + wu.repeat(1).map(() => Math.floor((Math.random() * 36))
201
- .toString(36)).take(4).toArray().join(''));
202
- return overriddenMonomerLib;
203
- }
@@ -0,0 +1,279 @@
1
+ import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
2
+ import {Rules, RuleReaction, getMonomerPairs} from './pt-rules';
3
+ import {InvalidReactionError, MonomerNotFoundError} from '../types';
4
+ import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
5
+
6
+ import * as grok from 'datagrok-api/grok';
7
+
8
+ import wu from 'wu';
9
+ import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
10
+ import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
11
+ import {IMonomerLib, IMonomerLibBase, Monomer, MonomerLibData, RGroup} from '@datagrok-libraries/bio/src/types';
12
+ import {RDModule, RDMol, RDReaction, MolList, RDReactionResult} from '@datagrok-libraries/chem-meta/src/rdkit-api';
13
+ import {HELM_REQUIRED_FIELD as REQ,
14
+ HELM_OPTIONAL_FIELDS as OPT, HELM_RGROUP_FIELDS} from '@datagrok-libraries/bio/src/utils/const';
15
+
16
+ export async function getOverriddenLibrary(rules: Rules): Promise<IMonomerLibBase> {
17
+ const monomerLibHelper = await getMonomerLibHelper();
18
+ const systemMonomerLib = monomerLibHelper.getMonomerLib();
19
+
20
+ const rdkit = await getRdKitModule();
21
+ const argLib: { [symbol: string]: Monomer } = {};
22
+
23
+ let names: string [] = [];
24
+ let monomers: Monomer [] = [];
25
+
26
+ for (let i = 0; i < rules.reactionRules.length; i++) {
27
+ try {
28
+ [names, monomers] = getNewMonomers(rdkit, systemMonomerLib, rules.reactionRules[i]);
29
+ } catch (e: any) {
30
+ names = [];
31
+ monomers = [];
32
+ console.error(e);
33
+ } finally {
34
+ for (let j = 0; j < names.length; j ++)
35
+ argLib[names[j]] = monomers[j];
36
+ }
37
+ }
38
+
39
+ const overrideMonomerLibData: MonomerLibData = {[PolymerTypes.PEPTIDE]: argLib};
40
+ const overriddenMonomerLib = systemMonomerLib.override(overrideMonomerLibData,
41
+ 'ST-PT-reactions.' + wu.repeat(1).map(() => Math.floor((Math.random() * 36))
42
+ .toString(36)).take(4).toArray().join(''));
43
+ return overriddenMonomerLib;
44
+ }
45
+
46
+ export function getNewMonomers(rdkit: RDModule, mLib: IMonomerLib, rule: RuleReaction): [string[], Monomer[]] {
47
+ const reacSmarts = rule.reaction;
48
+ const monomerName = rule.name;
49
+ const totalLength = rule.firstMonomers.length + rule.secondMonomers.length + 1;
50
+ const reactionMembers = rule.reaction.split('>>');
51
+ const reactants = reactionMembers[0].split('.');
52
+
53
+ const monomerNames = new Array<string>(totalLength);
54
+ const resMonomers = new Array<Monomer>(totalLength);
55
+ const rawMonomers = new Array<string>(totalLength);
56
+
57
+ const mainRxn = getReactionSmirks(rdkit, reacSmarts);
58
+
59
+ const reacCutFirst = `${reactants[0]}>>[C:1]`;
60
+ const reacCutSecond = `${reactants[1]}>>[C:2]`;
61
+
62
+ const rxnCutFirst = getReactionSmirks(rdkit, reacCutFirst);
63
+ const rxnCutSecond = getReactionSmirks(rdkit, reacCutSecond);
64
+
65
+ let counter = 0;
66
+ for (let i = 0; i < rule.firstMonomers.length; i++) {
67
+ const monomer = mLib.getMonomer('PEPTIDE', rule.firstMonomers[i]);
68
+ if (!monomer) throw new MonomerNotFoundError('PEPTIDE', rule.firstMonomers[i]);
69
+
70
+ const sMolBlock = cutReactant(rdkit, monomer.molfile, rxnCutFirst, monomer.name);
71
+ rawMonomers[counter] = sMolBlock;
72
+ monomerNames[counter] = `${monomer.symbol}_${monomerName}`;
73
+ counter++;
74
+ }
75
+ for (let i = 0; i < rule.secondMonomers.length; i++) {
76
+ const monomer = mLib.getMonomer('PEPTIDE', rule.secondMonomers[i]);
77
+ if (!monomer) throw new MonomerNotFoundError('PEPTIDE', rule.secondMonomers[i]);
78
+
79
+ const sMolBlock = cutReactant(rdkit, monomer.molfile, rxnCutSecond, monomer.name);
80
+ rawMonomers[counter] = sMolBlock;
81
+ monomerNames[counter] = `${monomer.symbol}_${monomerName}`;
82
+ counter++;
83
+ }
84
+
85
+ // const monomer1 = mLib.getMonomer('PEPTIDE', rule.firstMonomers[0]);
86
+ // const monomer2 = mLib.getMonomer('PEPTIDE', rule.secondMonomers[0]);
87
+ let mol: RDMol | null = null;
88
+ let pMolblock = '';
89
+ try {
90
+ mol = rdkit.get_mol(reactionMembers[1]);
91
+ pMolblock = mol?.get_molblock();//molP?.get_v3Kmolblock();//
92
+ } catch (err: any) {
93
+ const [errMsg, _errStack] = errInfo(err);
94
+ grok.shell.error(`Can not assemble monomer '${monomerName}': ${errMsg}.`);
95
+ throw err;
96
+ } finally {
97
+ mol?.delete();
98
+ }
99
+ //pMolblock = reactionMembers[1]//cutProduct(rdkit, monomer1?.molfile, monomer2?.molfile, mainRxn, monomerName);
100
+ rawMonomers[counter] = pMolblock;
101
+ monomerNames[counter] = monomerName;
102
+
103
+ //after RDKit works
104
+ for (let i = 0; i < totalLength - 1; i ++)
105
+ rawMonomers[i] = rawMonomers[i].replace('0.0000 C ', '0.0000 R# ').replace('M RGP 2', 'M RGP 3 1 3');
106
+ rawMonomers[totalLength - 1] = modProduct(rawMonomers[totalLength - 1]);
107
+
108
+ for (let i = 0; i < totalLength; i ++) {
109
+ const isProduct = i == totalLength - 1 ? true : false;
110
+ const resMonomer: Monomer = {
111
+ [REQ.SYMBOL]: monomerNames[i],
112
+ [REQ.NAME]: monomerNames[i],
113
+ [REQ.MOLFILE]: rawMonomers[i],
114
+ [REQ.AUTHOR]: '',
115
+ [REQ.ID]: 0,
116
+ [REQ.RGROUPS]: getNewGroups(isProduct),
117
+ [REQ.SMILES]: '',
118
+ [REQ.POLYMER_TYPE]: 'PEPTIDE',
119
+ [REQ.MONOMER_TYPE]: 'Backbone',
120
+ [REQ.CREATE_DATE]: null,
121
+ // // @ts-ignore
122
+ // lib: {source: 'Reaction'},
123
+ };
124
+
125
+ resMonomer[OPT.META] = Object.assign(resMonomer[OPT.META] ?? {},
126
+ {'colors': {'default': {line: '#2083D5', text: '#2083D5', background: '#F2F2F5'}}});
127
+
128
+ monomerNames[i] = monomerNames[i];
129
+ resMonomers[i] = resMonomer;
130
+ }
131
+ mainRxn.delete();
132
+ rxnCutFirst.delete();
133
+ rxnCutSecond.delete();
134
+ return [monomerNames, resMonomers];
135
+ }
136
+
137
+ function modProduct(product: string): string {
138
+ const fullMol = product.replace('M RAD', 'M RGP');
139
+ const lines = fullMol.split('\n');
140
+ const natoms = Number(lines[3].substring(0, 3));
141
+ const nbonds = Number(lines[3].substring(3, 6));
142
+ const rgpShift = 4 + natoms + nbonds;
143
+
144
+ const fAtom = Number(lines[rgpShift].substring(9, 13));
145
+ const sAtom = Number(lines[rgpShift].substring(17, 21));
146
+
147
+ lines[rgpShift] = lines[rgpShift].substring(0, 13) + ' 1' + lines[rgpShift].substring(17, 21) + ' 2';
148
+
149
+ lines[3 + fAtom] = lines[3 + fAtom].substring(0, 30) + ' R# 0 0 0 0 0 0 0 0 0 0 0 0';
150
+ lines[3 + sAtom] = lines[3 + sAtom].substring(0, 30) + ' R# 0 0 0 0 0 0 0 0 0 0 0 0';
151
+
152
+ let res = '';
153
+ for (let i = 0; i < lines.length; i++)
154
+ res += lines[i] + '\n';
155
+
156
+ return res;
157
+ }
158
+
159
+ function cutReactant(rdkit: RDModule, reactant: string, rxn: RDReaction, monomerName: string) {
160
+ let mols: MolList | null = null;
161
+ let mol: RDMol | null = null;
162
+ let rctns: RDReactionResult | null = null;
163
+ let molP: RDMol | null = null;
164
+ let molBlock = '';
165
+
166
+ try {
167
+ mols = new rdkit.MolList();
168
+ mol = rdkit.get_mol(reactant);
169
+ mols.append(mol);
170
+ rctns = rxn.run_reactants(mols, 1);
171
+ //const size = rctns.size();
172
+ const element = rctns.get(0);
173
+ molP = element.next();
174
+ molBlock = molP?.get_molblock();//molP?.get_v3Kmolblock();//
175
+ } catch (err: any) {
176
+ const [errMsg, _errStack] = errInfo(err);
177
+ grok.shell.error(`Can not assemble monomer '${monomerName}': ${errMsg}.`);
178
+ throw err;
179
+ } finally {
180
+ mols?.delete();
181
+ mol?.delete();
182
+ rctns?.delete();
183
+ molP?.delete();
184
+ }
185
+
186
+ return molBlock;
187
+ }
188
+
189
+ function getReactionSmirks(rdkit: RDModule, smirks: string): RDReaction {
190
+ let rxn: RDReaction | null = null;
191
+ try {
192
+ rxn = rdkit.get_rxn(smirks);
193
+ if (!rxn) throw new InvalidReactionError(smirks);
194
+ } catch (err: any) {
195
+ rxn?.delete();
196
+ const [errMsg, _errStack] = errInfo(err);
197
+ grok.shell.error(`Can not assemble monomer '${smirks}': ${errMsg}.`);
198
+ throw err;
199
+ } finally {
200
+
201
+ }
202
+ return rxn;
203
+ }
204
+
205
+ function getNewGroups(isProduct: boolean): RGroup[] {
206
+ if (isProduct) {
207
+ const groups = new Array<RGroup>(2);
208
+ const group1: RGroup = {
209
+ //@ts-ignore
210
+ [HELM_RGROUP_FIELDS.CAP_GROUP_SMILES_UPPERCASE]: '[*:1][H]',
211
+ [HELM_RGROUP_FIELDS.ALTERNATE_ID]: 'R1-H',
212
+ [HELM_RGROUP_FIELDS.CAP_GROUP_NAME]: 'H',
213
+ [HELM_RGROUP_FIELDS.LABEL]: 'R1'
214
+ };
215
+ const group2: RGroup = {
216
+ //@ts-ignore
217
+ [HELM_RGROUP_FIELDS.CAP_GROUP_SMILES_UPPERCASE]: '[*:2][H]',
218
+ [HELM_RGROUP_FIELDS.ALTERNATE_ID]: 'R2-H',
219
+ [HELM_RGROUP_FIELDS.CAP_GROUP_NAME]: 'H',
220
+ [HELM_RGROUP_FIELDS.LABEL]: 'R2'
221
+ };
222
+
223
+ groups[0] = group1;
224
+ groups[1] = group2;
225
+
226
+ return groups;
227
+ } else {
228
+ const group: RGroup = {
229
+ //@ts-ignore
230
+ [HELM_RGROUP_FIELDS.CAP_GROUP_SMILES_UPPERCASE]: '[*:3][H]',
231
+ [HELM_RGROUP_FIELDS.ALTERNATE_ID]: 'R3-H',
232
+ [HELM_RGROUP_FIELDS.CAP_GROUP_NAME]: 'H',
233
+ [HELM_RGROUP_FIELDS.LABEL]: 'R3'
234
+ };
235
+
236
+ return [group];
237
+ }
238
+ }
239
+
240
+ function getSyntheticMolBlock(rdkit: RDModule, reaction: string,
241
+ mb1: string, mb2: string, monomerName: string): string {
242
+ let rxn: RDReaction | null = null;
243
+ let mols: MolList | null = null;
244
+ let mol1: RDMol | null = null;
245
+ let mol2: RDMol | null = null;
246
+ let rctns: RDReactionResult | null = null;
247
+ let molP: RDMol | null = null;
248
+ let molBlock = '';
249
+
250
+ try {
251
+ rxn = rdkit.get_rxn(reaction);
252
+ if (!rxn) throw new InvalidReactionError(reaction);
253
+ mols = new rdkit.MolList();
254
+ mol1 = rdkit.get_mol(mb1!);
255
+ mol2 = rdkit.get_mol(mb2!);
256
+ mols.append(mol1!);
257
+ mols.append(mol2!);
258
+
259
+ rctns = rxn.run_reactants(mols, 1);
260
+ //const size = rctns.size();
261
+ const element = rctns.get(0);
262
+
263
+ molP = element.next();
264
+ molBlock = molP?.get_molblock();//molP?.get_v3Kmolblock();//
265
+ } catch (err: any) {
266
+ const [errMsg, _errStack] = errInfo(err);
267
+ grok.shell.error(`Can not assemble monomer '${monomerName}': ${errMsg}.`);
268
+ throw err;
269
+ } finally {
270
+ rxn?.delete();
271
+ mols?.delete();
272
+ mol1?.delete();
273
+ mol2?.delete();
274
+ rctns?.delete();
275
+ molP?.delete();
276
+ }
277
+
278
+ return molBlock;
279
+ }
@@ -0,0 +1,114 @@
1
+ import {IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
2
+ import {Atom, IHelmBio, HelmMol, HelmType, JSDraw2ModuleType, OrgType} from '@datagrok-libraries/bio/src/helm/types';
3
+ import {HelmTypes} from '@datagrok-libraries/bio/src/helm/consts';
4
+ import {Linkage} from './pt-misc';
5
+
6
+ declare const JSDraw2: JSDraw2ModuleType;
7
+ declare const org: OrgType;
8
+
9
+
10
+ export type PtBio = IHelmBio & { i: number, j: number };
11
+ type PtAtom = Atom<HelmType, PtBio>
12
+
13
+ export function getHelmMol(linkages: Linkage[], mainFragments: string[][], helmHelper: IHelmHelper): HelmMol {
14
+ const resHwe = helmHelper.createHelmWebEditor();
15
+ const resMol = resHwe.editor.m;
16
+
17
+ let counter = 0;
18
+ const p = new JSDraw2.Point(0, 0);
19
+ for (let i = 0; i < mainFragments.length; i++) {
20
+ for (let j = 0; j < mainFragments[i].length; j++) {
21
+ if (!!mainFragments[i][j]) {
22
+ const elem = mainFragments[i][j];
23
+ const bio: PtBio = {type: HelmTypes.AA, i: i, j: j, continuousId: counter};
24
+ const atom = new JSDraw2.Atom<HelmType, IHelmBio>(p, elem, bio);
25
+ resMol.addAtom(atom);
26
+
27
+ if (j !== 0) {
28
+ const atom1 = resMol.atoms[counter - 1];
29
+ const atom2 = resMol.atoms[counter];
30
+ const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
31
+ bond.r1 = 2;
32
+ bond.r2 = 1;
33
+ resMol.addBond(bond);
34
+ }
35
+
36
+ counter++;
37
+ p.x += JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
38
+ }
39
+ p.y += 4 * JSDraw2.Editor.BONDLENGTH; // Inspired by HELMWebEditor
40
+ }
41
+ }
42
+
43
+ for (let i = 0; i < linkages.length; i++) {
44
+ const atom1 = resMol.atoms[linkages[i].fMonomer - 1];
45
+ const atom2 = resMol.atoms[linkages[i].sMonomer - 1];
46
+ const bond = new JSDraw2.Bond<HelmType, IHelmBio>(atom1, atom2);
47
+ bond.r1 = linkages[i].fR;
48
+ bond.r2 = linkages[i].sR;
49
+ resMol.addBond(bond);
50
+ }
51
+ return resMol;
52
+ }
53
+
54
+ export function helmMolToNotation(mol: HelmMol): string {
55
+ const atoms = mol.atoms;
56
+ const bonds = mol.bonds;
57
+ const chains: number[] = [];
58
+ const specialBonds: number[] = [];
59
+ for (let i = 0; i < bonds.length!; i++) {
60
+ //@ts-ignore
61
+ if (bonds[i].a1.bio.i !== bonds[i].a2.bio.i)
62
+ specialBonds.push(i);
63
+ }
64
+
65
+ for (let i = 0; i < atoms.length!; i++) {
66
+ //@ts-ignore
67
+ const atomChain = atoms[i].bio?.i;
68
+ if (atomChain + 1 > chains.length)
69
+ chains.push(1);
70
+ else
71
+ chains[atomChain]++;
72
+ }
73
+
74
+ const simpleChains: string[][] = new Array(chains.length);
75
+ let counter = 0;
76
+ for (let i = 0; i < chains.length!; i++) {
77
+ const simpleChain: string[] = new Array(chains[i]);
78
+ for (let j = 0; j < chains[i]; j++) {
79
+ simpleChain[j] = atoms[counter].elem;
80
+ counter++;
81
+ }
82
+
83
+ simpleChains[i] = simpleChain;
84
+ }
85
+
86
+ let res = '';
87
+ for (let i = 0; i < simpleChains.length; i++) {
88
+ let chainAdd = '';
89
+
90
+ for (let j = 0; j < simpleChains[i].length; j++)
91
+ chainAdd += `${j == 0 ? '' : '-'}${simpleChains[i][j]}`;
92
+
93
+ if (i !== 0) {
94
+ const rxp = /(\(.\d+\))/;
95
+ const match = chainAdd.match(rxp);
96
+ chainAdd = chainAdd.replace(match?.[0]!, '');
97
+ const group = match ? match?.[0]! : '';
98
+ chainAdd = `${group}{${chainAdd}}`;
99
+ } else {
100
+ if (simpleChains.length > 1) {
101
+ //@ts-ignore
102
+ const firstAtomLinks = bonds[specialBonds[0]].a1.bio.i == 0 && bonds[specialBonds[0]].a1.bio.j == 0;
103
+ //@ts-ignore
104
+ const secondAtomLinks = bonds[specialBonds[0]].a2.bio.i == 1 && bonds[specialBonds[0]].a1.bio.j == 0;
105
+ if (firstAtomLinks && secondAtomLinks)
106
+ chainAdd += '-';
107
+ }
108
+ }
109
+
110
+ res += chainAdd;
111
+ }
112
+
113
+ return res;
114
+ }