@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.
- package/.eslintrc.json +2 -2
- package/CHANGELOG.md +6 -0
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +2 -2
- package/src/package.ts +1 -0
- package/src/polytool/conversion/pt-chain.ts +38 -635
- package/src/polytool/conversion/pt-conversion.ts +2 -3
- package/src/polytool/conversion/pt-misc.ts +8 -182
- package/src/polytool/conversion/pt-synthetic.ts +279 -0
- package/src/polytool/conversion/pt-tools-helmmol.ts +114 -0
- package/src/polytool/conversion/pt-tools-parse.ts +356 -0
- package/src/polytool/pt-dialog.ts +1 -1
- package/src/polytool/pt-enumerate-seq-dialog.ts +1 -1
- package/src/polytool/pt-enumeration-helm.ts +7 -5
- package/src/polytool/pt-unrule.ts +3 -3
- package/src/tests/polytool-chain-from-notation-tests.ts +34 -33
- package/src/tests/polytool-chain-parse-notation-tests.ts +2 -2
- package/src/tests/polytool-convert-tests.ts +14 -14
- package/src/tests/polytool-detectors-custom-notation-test.ts +1 -1
- package/src/tests/toAtomicLevel-tests.ts +4 -4
- package/src/utils/cyclized.ts +6 -4
|
@@ -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.
|
|
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
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
+
}
|