Skip to content

Commit

Permalink
#3298 - Add simple atom query primitives to the query specific proper…
Browse files Browse the repository at this point in the history
…ties
  • Loading branch information
AKZhuk committed Sep 14, 2023
1 parent a553367 commit 57e9d60
Show file tree
Hide file tree
Showing 18 changed files with 329 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ test.describe('Right-click menu', () => {
await page.getByText('Ring bond count').click();
await takeEditorScreenshot(page);
await page.getByRole('button', { name: 'As drawn' }).first().click();
await page.getByText('Substitution count').click();
await page.getByText('Aromaticity').click();
await takeEditorScreenshot(page);
await page.getByRole('button', { name: '6' }).last().click();
await page.getByRole('button', { name: 'aliphatic' }).click();
await page.getByText('Unsaturated').first().click();
await takeEditorScreenshot(page);
await page.getByRole('button', { name: 'Saturated' }).last().click();
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion ketcher-autotests/tests/utils/canvas/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ export enum SORT_TYPE {
ASC_X = 'ASC_X',
ASC_Y = 'ASC_Y',
}

export type Aromaticity = 'aromatic' | 'aliphatic';
export type Chirality = '@' | '@@' | '@?' | '@@?';
export type AtomAttributes = {
label?: string;
charge?: number;
Expand All @@ -15,6 +16,15 @@ export type AtomAttributes = {
explicitValence?: number;
implicitH?: number;
ringBondCount?: number;
aromaticity?: Aromaticity | null;
degree?: number | null;
implicitHCount?: number | null;
ringMembership?: number | null;
ringSize?: number | null;
connectivity?: number | null;
ringConnectivity?: number | null;
chirality?: Chirality | null;
atomicMass?: number | null;
substitutionCount?: number;
unsaturatedAtom?: number;
hCount?: number;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { selectionKeys } from '../shared/constants';
import { EditorSelection } from '../editor.types';

export type AtomAttributeName = keyof AtomAttributes;
export type AtomAttributeValue = AtomAttributes[AtomAttributeName];

export function atomGetAttr(
restruct: ReStruct,
Expand Down
88 changes: 71 additions & 17 deletions packages/ketcher-core/src/application/render/restruct/reatom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1071,29 +1071,83 @@ function getAamText(atom) {

function getQueryAttrsText(atom) {
let queryAttrsText = '';
if (atom.a.ringBondCount !== 0) {
if (atom.a.ringBondCount > 0) {
queryAttrsText += 'rb' + atom.a.ringBondCount.toString();
} else if (atom.a.ringBondCount === -1) queryAttrsText += 'rb0';
else if (atom.a.ringBondCount === -2) queryAttrsText += 'rb*';
const addComma = () => {
if (queryAttrsText.length > 0) queryAttrsText += ',';
};
const {
ringBondCount,
substitutionCount,
unsaturatedAtom,
hCount,
aromaticity,
degree,
implicitHCount,
ringMembership,
ringSize,
connectivity,
ringConnectivity,
chirality,
atomicMass,
} = atom.a;
if (ringBondCount !== 0) {
if (ringBondCount > 0) {
queryAttrsText += 'rb' + ringBondCount.toString();
} else if (ringBondCount === -1) queryAttrsText += 'rb0';
else if (ringBondCount === -2) queryAttrsText += 'rb*';
else throw new Error('Ring bond count invalid');
}
if (atom.a.substitutionCount !== 0) {
if (queryAttrsText.length > 0) queryAttrsText += ',';
if (atom.a.substitutionCount > 0) {
queryAttrsText += 's' + atom.a.substitutionCount.toString();
} else if (atom.a.substitutionCount === -1) queryAttrsText += 's0';
else if (atom.a.substitutionCount === -2) queryAttrsText += 's*';
if (substitutionCount !== 0) {
addComma();
if (substitutionCount > 0) {
queryAttrsText += 's' + substitutionCount.toString();
} else if (substitutionCount === -1) queryAttrsText += 's0';
else if (substitutionCount === -2) queryAttrsText += 's*';
else throw new Error('Substitution count invalid');
}
if (atom.a.unsaturatedAtom > 0) {
if (queryAttrsText.length > 0) queryAttrsText += ',';
if (atom.a.unsaturatedAtom === 1) queryAttrsText += 'u';
if (unsaturatedAtom > 0) {
addComma();
if (unsaturatedAtom === 1) queryAttrsText += 'u';
else throw new Error('Unsaturated atom invalid value');
}
if (atom.a.hCount > 0) {
if (queryAttrsText.length > 0) queryAttrsText += ',';
queryAttrsText += 'H' + (atom.a.hCount - 1).toString();
if (hCount > 0) {
addComma();
queryAttrsText += 'H' + (hCount - 1).toString();
}
if (aromaticity !== null) {
addComma();
queryAttrsText += aromaticity === 'aromatic' ? 'a' : 'A';
}
if (degree !== null) {
addComma();
queryAttrsText += `D<${degree}>`;
}
if (implicitHCount !== null) {
addComma();
queryAttrsText += `h<${implicitHCount}>`;
}
if (ringMembership !== null) {
addComma();
queryAttrsText += `R<${ringMembership}>`;
}
if (ringSize !== null) {
addComma();
queryAttrsText += `r<${ringSize}>`;
}
if (connectivity !== null) {
addComma();
queryAttrsText += `X<${connectivity}>`;
}
if (ringConnectivity !== null) {
addComma();
queryAttrsText += `x<${ringConnectivity}>`;
}
if (chirality !== null) {
addComma();
queryAttrsText += chirality;
}
if (atomicMass !== null) {
addComma();
queryAttrsText += `<${atomicMass}>`;
}
return queryAttrsText;
}
Expand Down
55 changes: 55 additions & 0 deletions packages/ketcher-core/src/domain/entities/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ enum CIP {
r = 'r',
}

export type Aromaticity = 'aromatic' | 'aliphatic';
export type Chirality = '@' | '@@' | '@?' | '@@?';
export interface AtomAttributes {
stereoParity?: number;
stereoLabel?: string | null;
Expand All @@ -68,6 +70,14 @@ export interface AtomAttributes {
unsaturatedAtom?: number;
substitutionCount?: number;
ringBondCount?: number;
aromaticity?: Aromaticity | null;
degree?: number | null;
ringMembership?: number | null;
ringSize?: number | null;
connectivity?: number | null;
ringConnectivity?: number | null;
chirality?: Chirality | null;
atomicMass?: number | null;
explicitValence?: number;
/**
* Rgroup member attachment points
Expand Down Expand Up @@ -125,6 +135,14 @@ export class Atom {
substitutionCount: 0,
unsaturatedAtom: 0,
hCount: 0,
aromaticity: null,
degree: null,
ringMembership: null,
ringSize: null,
connectivity: null,
ringConnectivity: null,
chirality: null,
atomicMass: null,
atomList: null,
invRet: 0,
exactChangeFlag: 0,
Expand All @@ -150,6 +168,14 @@ export class Atom {
charge: number;
explicitValence: number;
ringBondCount: number;
aromaticity: Aromaticity | null;
degree: number | null;
ringMembership: number | null;
ringSize: number | null;
connectivity: number | null;
ringConnectivity: number | null;
chirality: Chirality | null;
atomicMass: number | null;
unsaturatedAtom: number;
substitutionCount: number;
valence: number;
Expand Down Expand Up @@ -212,6 +238,35 @@ export class Atom {
attributes.ringBondCount,
Atom.attrlist.ringBondCount,
);
this.aromaticity = getValueOrDefault(
attributes.aromaticity,
Atom.attrlist.aromaticity,
);
this.degree = getValueOrDefault(attributes.degree, Atom.attrlist.degree);
this.ringMembership = getValueOrDefault(
attributes.ringMembership,
Atom.attrlist.ringMembership,
);
this.ringSize = getValueOrDefault(
attributes.ringSize,
Atom.attrlist.ringSize,
);
this.connectivity = getValueOrDefault(
attributes.connectivity,
Atom.attrlist.connectivity,
);
this.ringConnectivity = getValueOrDefault(
attributes.ringConnectivity,
Atom.attrlist.ringConnectivity,
);
this.chirality = getValueOrDefault(
attributes.chirality,
Atom.attrlist.chirality,
);
this.atomicMass = getValueOrDefault(
attributes.atomicMass,
Atom.attrlist.atomicMass,
);
this.substitutionCount = getValueOrDefault(
attributes.substitutionCount,
Atom.attrlist.substitutionCount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
import { Elements } from 'domain/constants';
import { ifDef } from 'utilities';
import { mergeFragmentsToStruct } from './mergeFragmentsToStruct';
import { AtomAttributeName } from 'application/editor';

export function toRlabel(values) {
let res = 0;
Expand Down Expand Up @@ -82,7 +83,19 @@ export function moleculeToStruct(ketItem: any): Struct {

export function atomToStruct(source) {
const params: any = {};

const queryAttribute: AtomAttributeName[] = [
'ringBondCount',
'substitutionCount',
'hCount',
'aromaticity',
'degree',
'ringMembership',
'connectivity',
'ringSize',
'ringConnectivity',
'chirality',
'atomicMass',
];
ifDef(params, 'label', source.label);
ifDef(params, 'alias', source.alias);
ifDef(params, 'pp', {
Expand All @@ -101,10 +114,11 @@ export function atomToStruct(source) {
ifDef(params, 'stereoParity', source.stereoParity);
ifDef(params, 'weight', source.weight);
// query
ifDef(params, 'ringBondCount', source.ringBondCount);
ifDef(params, 'substitutionCount', source.substitutionCount);
queryAttribute.forEach((attributeName) => {
ifDef(params, attributeName, source[attributeName]);
});
ifDef(params, 'unsaturatedAtom', Number(Boolean(source.unsaturatedAtom)));
ifDef(params, 'hCount', source.hCount);

// reaction
ifDef(params, 'aam', source.mapping);
ifDef(params, 'invRet', source.invRet);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ function atomToKet(source) {
ifDef(result, 'substitutionCount', source.substitutionCount, 0);
ifDef(result, 'unsaturatedAtom', !!source.unsaturatedAtom, false);
ifDef(result, 'hCount', source.hCount, 0);
ifDef(result, 'aromaticity', source.aromaticity);
ifDef(result, 'degree', source.degree);
ifDef(result, 'ringMembership', source.ringMembership);
ifDef(result, 'connectivity', source.connectivity);
ifDef(result, 'ringSize', source.ringSize);
ifDef(result, 'ringConnectivity', source.ringConnectivity);
ifDef(result, 'chirality', source.chirality);
ifDef(result, 'atomicMass', source.atomicMass, 0);

// reaction
ifDef(result, 'mapping', parseInt(source.aam), 0);
ifDef(result, 'invRet', source.invRet, 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default function ButtonGroup<T>({
{buttons.map(({ label, value: buttonValue }) => (
<ToggleButton
key={label}
value={Number(buttonValue)}
value={Number(buttonValue) || ''}
onClick={(event) => handleChange(event, buttonValue)}
className={clsx(classes.button, {
[classes.selected]: buttonValue === value,
Expand Down
10 changes: 10 additions & 0 deletions packages/ketcher-react/src/script/ui/data/convert/structconv.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ export function fromAtom(satom) {
radical: satom.radical,
invRet: satom.invRet,
exactChangeFlag: !!satom.exactChangeFlag,
aromaticity: satom.aromaticity,
degree: satom.degree,
implicitHCount: satom.implicitHCount,
ringMembership: satom.ringMembership,
ringSize: satom.ringSize,
connectivity: satom.connectivity,
ringConnectivity: satom.ringConnectivity,
chirality: satom.chirality,
atomicMass: satom.atomicMass === null ? '' : satom.atomicMass.toString(),
ringBondCount: satom.ringBondCount,
substitutionCount: satom.substitutionCount,
unsaturatedAtom: !!satom.unsaturatedAtom,
Expand All @@ -108,6 +117,7 @@ export function toAtom(atom) {
unsaturatedAtom: +(atom.unsaturatedAtom ?? false),
});
if (charge !== undefined) conv.charge = charge;
conv.atomicMass = atom.atomicMass === '' ? null : Number(atom.atomicMass);
return conv;
}

Expand Down
Loading

0 comments on commit 57e9d60

Please sign in to comment.