Skip to content

Commit

Permalink
- in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
rrodionov91 committed May 30, 2024
1 parent 2da4387 commit 8970344
Show file tree
Hide file tree
Showing 11 changed files with 158 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class MacromoleculesConverter {
return Number(attachmentPointName?.replace('R', ''));
}

private static findAttachmentPointAtom(
public static findAttachmentPointAtom(
polymerBond: PolymerBond,
monomer: BaseMonomer,
monomerToAtomIdMap: Map<BaseMonomer, Map<number, number>>,
Expand Down
13 changes: 11 additions & 2 deletions packages/ketcher-core/src/application/render/restruct/reatom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,18 @@ class ReAtom extends ReObject {
const { options } = render;
const sgroups = render.ctab.sgroups;
const functionalGroups = render.ctab.molecule.functionalGroups;
const struct = render.ctab.molecule;
const atomId = struct.atoms.keyOf(atom) as number;

if (
FunctionalGroup.isAtomInContractedFunctionalGroup(
atom,
sgroups,
functionalGroups,
true,
)
) ||
(Atom.isSuperatomLeavingGroupAtom(struct, atomId) &&
Atom.isAttachmentAtomHasExternalConnections(struct, atomId))
) {
return null;
}
Expand All @@ -171,13 +175,18 @@ class ReAtom extends ReObject {
const { options } = render;
const sgroups = render.ctab.sgroups;
const functionalGroups = render.ctab.molecule.functionalGroups;
const struct = render.ctab.molecule;
const atomId = struct.atoms.keyOf(atom) as number;

if (
FunctionalGroup.isAtomInContractedFunctionalGroup(
atom,
sgroups,
functionalGroups,
true,
)
) ||
(Atom.isSuperatomLeavingGroupAtom(struct, atomId) &&
Atom.isAttachmentAtomHasExternalConnections(struct, atomId))
) {
return null;
}
Expand Down
19 changes: 5 additions & 14 deletions packages/ketcher-core/src/application/render/restruct/rebond.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ class ReBond extends ReObject {
bond,
sgroups,
functionalGroups,
)
) ||
Bond.isBondToHiddenLeavingGroup(restruct.molecule, bond)
) {
return null;
}
Expand All @@ -282,7 +283,8 @@ class ReBond extends ReObject {
bond,
sgroups,
functionalGroups,
)
) ||
Bond.isBondToHiddenLeavingGroup(restruct.molecule, bond)
) {
return null;
}
Expand All @@ -299,19 +301,8 @@ class ReBond extends ReObject {
const bond = restruct.molecule.bonds.get(bid)!;
const sgroups = restruct.molecule.sgroups;
const functionalGroups = restruct.molecule.functionalGroups;
const beginSuperatomAttachmentPoint =
Atom.getSuperAtomAttachmentPointByLeavingGroup(struct, bond.begin);
const endSuperatomAttachmentPoint =
Atom.getSuperAtomAttachmentPointByLeavingGroup(struct, bond.end);

if (
(beginSuperatomAttachmentPoint &&
Atom.isAttachmentAtomHasExternalConnections(struct, bond.begin) &&
bond.end === beginSuperatomAttachmentPoint.atomId) ||
(endSuperatomAttachmentPoint &&
Atom.isAttachmentAtomHasExternalConnections(struct, bond.end) &&
bond.begin === endSuperatomAttachmentPoint.atomId)
) {
if (Bond.isBondToHiddenLeavingGroup(struct, bond)) {
return;
}

Expand Down
4 changes: 1 addition & 3 deletions packages/ketcher-core/src/domain/entities/BaseMonomer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,9 +412,7 @@ export abstract class BaseMonomer extends DrawingEntity {
},
type:
this.attachmentPointNumberToType[
getAttachmentPointLabelWithBinaryShift(
superatomAttachmentPointIndex + 1,
)
superatomAttachmentPointIndex + 1
] || this.attachmentPointNumberToType.moreThanTwo,
});
},
Expand Down
7 changes: 7 additions & 0 deletions packages/ketcher-core/src/domain/entities/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,13 @@ export class Atom extends BaseMicromoleculeEntity {

return isAttachmentAtomHasExternalConnection;
}

public static isHiddenLeavingGroupAtom(struct: Struct, atomId: number) {
return (
Atom.isSuperatomLeavingGroupAtom(struct, atomId) &&
Atom.isAttachmentAtomHasExternalConnections(struct, atomId)
);
}
}

export function radicalElectrons(radical: any) {
Expand Down
16 changes: 16 additions & 0 deletions packages/ketcher-core/src/domain/entities/bond.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,20 @@ export class Bond extends BaseMicromoleculeEntity {
const sGroupsWithEndAtom = struct.atoms.get(this.end)?.sgs || new Pile();
return sGroupsWithBeginAtom?.intersection(sGroupsWithEndAtom);
}

public static isBondToHiddenLeavingGroup(struct: Struct, bond: Bond) {
const beginSuperatomAttachmentPoint =
Atom.getSuperAtomAttachmentPointByLeavingGroup(struct, bond.begin);
const endSuperatomAttachmentPoint =
Atom.getSuperAtomAttachmentPointByLeavingGroup(struct, bond.end);

return (
(beginSuperatomAttachmentPoint &&
Atom.isAttachmentAtomHasExternalConnections(struct, bond.begin) &&
bond.end === beginSuperatomAttachmentPoint.atomId) ||
(endSuperatomAttachmentPoint &&
Atom.isAttachmentAtomHasExternalConnections(struct, bond.end) &&
bond.begin === endSuperatomAttachmentPoint.atomId)
);
}
}
8 changes: 6 additions & 2 deletions packages/ketcher-core/src/domain/entities/struct.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,12 +183,16 @@ export class Struct {
return atomSet;
}

getFragment(fid: number | number[], copyNonFragmentObjects = true): Struct {
getFragment(
fid: number | number[],
copyNonFragmentObjects = true,
aidMap?: Map<number, number>,
): Struct {
return this.clone(
this.getFragmentIds(fid),
null,
true,
undefined,
aidMap,
copyNonFragmentObjects ? undefined : new Pile(),
copyNonFragmentObjects ? undefined : new Pile(),
copyNonFragmentObjects ? undefined : new Pile(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,57 @@ import { IKetConnection } from 'application/formatters/types/ket';
import { Command } from 'domain/entities/Command';
import { DrawingEntitiesManager } from 'domain/entities/DrawingEntitiesManager';
import assert from 'assert';
import { getAttachmentPointLabel } from 'domain/helpers/attachmentPointCalculations';

export function polymerBondToDrawingEntity(
connection: IKetConnection,
drawingEntitiesManager: DrawingEntitiesManager,
monomerIdsMap: { [monomerIdFromKet: string]: number },
atomIdMap: Map<number, number>,
) {
const command = new Command();
// TODO remove assertion when group connections will be supported on indigo side
assert(connection.endpoint1.monomerId);
assert(connection.endpoint2.monomerId);
const firstMonomer = drawingEntitiesManager.monomers.get(
Number(monomerIdsMap[connection.endpoint1.monomerId]),
Number(
monomerIdsMap[
connection.endpoint1.monomerId || connection.endpoint1.moleculeId
],
),
);
const secondMonomer = drawingEntitiesManager.monomers.get(
Number(monomerIdsMap[connection.endpoint2.monomerId]),
Number(
monomerIdsMap[
connection.endpoint2.monomerId || connection.endpoint2.moleculeId
],
),
);

assert(firstMonomer);
assert(secondMonomer);
assert(connection.endpoint1.attachmentPointId);
assert(connection.endpoint2.attachmentPointId);
command.merge(
drawingEntitiesManager.createPolymerBond(
firstMonomer,
secondMonomer,
connection.endpoint1.attachmentPointId,
connection.endpoint2.attachmentPointId,
connection.endpoint1.attachmentPointId ||
getAttachmentPointLabel(
firstMonomer.monomerItem.struct.sgroups
.get(0)
.getAttachmentPoints()
.findIndex(
(attachmentPoint) =>
attachmentPoint.atomId ===
atomIdMap.get(connection.endpoint1.atomId),
) + 1,
),
connection.endpoint2.attachmentPointId ||
getAttachmentPointLabel(
secondMonomer.monomerItem.struct.sgroups
.get(0)
.getAttachmentPoints()
.findIndex(
(attachmentPoint) =>
attachmentPoint.atomId ===
atomIdMap.get(connection.endpoint2.atomId),
) + 1,
),
),
);
return command;
Expand Down
93 changes: 69 additions & 24 deletions packages/ketcher-core/src/domain/serializers/ket/ketSerializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ import { MacromoleculesConverter } from 'application/editor/MacromoleculesConver
import { getAttachmentPointLabelWithBinaryShift } from 'domain/helpers/attachmentPointCalculations';
import { isNumber } from 'lodash';
import { MonomerItemType } from 'domain/types';
import { PolymerBond } from 'domain/entities/PolymerBond';

function parseNode(node: any, struct: any) {
const type = node.type;
Expand Down Expand Up @@ -197,13 +198,7 @@ export class KetSerializer implements Serializer<Struct> {
connection: IKetConnection,
editor: CoreEditor,
) {
if (
connection.connectionType !== KetConnectionType.SINGLE ||
!connection.endpoint1.monomerId ||
!connection.endpoint2.monomerId ||
!connection.endpoint1.attachmentPointId ||
!connection.endpoint2.attachmentPointId
) {
if (connection.connectionType !== KetConnectionType.SINGLE) {
editor.events.error.dispatch('Error during file parsing');
return true;
}
Expand Down Expand Up @@ -413,10 +408,12 @@ export class KetSerializer implements Serializer<Struct> {
const fragments = MacromoleculesConverter.getFragmentsGroupedBySgroup(
deserializedMicromolecules,
);
const atomIdMap = new Map<number, number>();
fragments.forEach((_fragment) => {
const fragmentStruct = deserializedMicromolecules.getFragment(
_fragment,
false,
atomIdMap,
);
const fragmentBbox = fragmentStruct.getCoordBoundingBox();
const monomerAdditionCommand = drawingEntitiesManager.addMonomer(
Expand All @@ -438,6 +435,8 @@ export class KetSerializer implements Serializer<Struct> {
fragmentBbox.max.y - (fragmentBbox.max.y - fragmentBbox.min.y) / 2,
),
);
const monomer = monomerAdditionCommand.operations[0].monomer;
monomerIdsMap[`mol${fragmentNumber - 1}`] = monomer?.id;
command.merge(monomerAdditionCommand);
fragmentNumber++;
});
Expand All @@ -449,6 +448,7 @@ export class KetSerializer implements Serializer<Struct> {
connection,
drawingEntitiesManager,
monomerIdsMap,
atomIdMap,
);
command.merge(bondAdditionCommand);
break;
Expand All @@ -469,6 +469,31 @@ export class KetSerializer implements Serializer<Struct> {
return this.deserializeToStruct(fileContent);
}

getConnectionMonomerEndpoint(monomer: BaseMonomer, polymerBond: PolymerBond) {
return {
monomerId: setMonomerPrefix(monomer.id),
attachmentPointId: monomer.getAttachmentPointByBond(polymerBond),
};
}

getConnectionMoleculeEndpoint(
monomer: BaseMonomer,
polymerBond: PolymerBond,
monomerToAtomIdMap: Map<BaseMonomer, Map<number, number>>,
struct: Struct,
) {
const atomId = MacromoleculesConverter.findAttachmentPointAtom(
polymerBond,
monomer,
monomerToAtomIdMap,
) as number;

return {
moleculeId: `mol${struct.atoms.get(atomId)?.fragment}`,
atomId,
};
}

serializeMacromolecules(
struct: Struct,
drawingEntitiesManager: DrawingEntitiesManager,
Expand All @@ -480,13 +505,23 @@ export class KetSerializer implements Serializer<Struct> {
templates: [],
},
};
const monomerToAtomIdMap = new Map<BaseMonomer, Map<number, number>>();

drawingEntitiesManager.monomers.forEach((monomer) => {
if (
monomer instanceof Chem &&
monomer.monomerItem.props.isMicromoleculeFragment
) {
monomer.monomerItem.struct.mergeInto(struct);
const atomIdMap = new Map<number, number>();
monomer.monomerItem.struct.mergeInto(
struct,
null,
null,
false,
false,
atomIdMap,
);
monomerToAtomIdMap.set(monomer, atomIdMap);
} else {
const templateId =
monomer.monomerItem.props.id ||
Expand Down Expand Up @@ -533,24 +568,32 @@ export class KetSerializer implements Serializer<Struct> {
});
drawingEntitiesManager.polymerBonds.forEach((polymerBond) => {
assert(polymerBond.secondMonomer);
if (
polymerBond.firstMonomer.monomerItem.props.isMicromoleculeFragment ||
polymerBond.secondMonomer.monomerItem.props.isMicromoleculeFragment
) {
return;
}
fileContent.root.connections.push({
connectionType: KetConnectionType.SINGLE,
endpoint1: {
monomerId: setMonomerPrefix(polymerBond.firstMonomer.id),
attachmentPointId:
polymerBond.firstMonomer.getAttachmentPointByBond(polymerBond),
},
endpoint2: {
monomerId: setMonomerPrefix(polymerBond.secondMonomer.id),
attachmentPointId:
polymerBond.secondMonomer?.getAttachmentPointByBond(polymerBond),
},
endpoint1: polymerBond.firstMonomer.monomerItem.props
.isMicromoleculeFragment
? this.getConnectionMoleculeEndpoint(
polymerBond.firstMonomer,
polymerBond,
monomerToAtomIdMap,
struct,
)
: this.getConnectionMonomerEndpoint(
polymerBond.firstMonomer,
polymerBond,
),
endpoint2: polymerBond.secondMonomer.monomerItem.props
.isMicromoleculeFragment
? this.getConnectionMoleculeEndpoint(
polymerBond.secondMonomer,
polymerBond,
monomerToAtomIdMap,
struct,
)
: this.getConnectionMonomerEndpoint(
polymerBond.secondMonomer,
polymerBond,
),
});
});

Expand All @@ -577,6 +620,8 @@ export class KetSerializer implements Serializer<Struct> {
const { serializedMacromolecules, micromoleculesStruct } =
this.serializeMacromolecules(new Struct(), drawingEntitiesManager);

micromoleculesStruct.enableInitiallySelected();

const serializedMicromoleculesStruct = JSON.parse(
this.serializeMicromolecules(micromoleculesStruct),
);
Expand Down
Loading

0 comments on commit 8970344

Please sign in to comment.