/** * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose */ import { Structure, Unit } from '../../../mol-model/structure'; import { StructureElement } from '../../../mol-model/structure/structure'; import { Elements, isHalogen } from '../../../mol-model/structure/model/properties/atomic/types'; import { ElementSymbol, BondType } from '../../../mol-model/structure/model/types'; import { eachBondedAtom, bondCount, typeSymbol, bondToElementCount } from './util'; function isAromatic(unit: Unit.Atomic, index: StructureElement.UnitIndex) { // TODO also extend unit.rings with geometry/composition-based aromaticity detection and use it here in addition const { offset, edgeProps } = unit.bonds; for (let i = offset[index], il = offset[index + 1]; i < il; ++i) { if (BondType.is(BondType.Flag.Aromatic, edgeProps.flags[i])) return true; } return false; } function bondToCarbonylCount(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let carbonylCount = 0; eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => { if (isCarbonyl(structure, unit, index)) carbonylCount += 1; }); return carbonylCount; } // /** * Nitrogen in a quaternary amine */ export function isQuaternaryAmine(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { return ( typeSymbol(unit, index) === Elements.N && bondCount(structure, unit, index) === 4 && bondToElementCount(structure, unit, index, Elements.H) === 0 ); } /** * Nitrogen in a tertiary amine */ export function isTertiaryAmine(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex, idealValence: number) { return ( typeSymbol(unit, index) === Elements.N && bondCount(structure, unit, index) === 4 && idealValence === 3 ); } /** * Nitrogen in an imide */ export function isImide(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let flag = false; if (typeSymbol(unit, index) === Elements.N && (bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H)) === 2 ) { flag = bondToCarbonylCount(structure, unit, index) === 2; } return flag; } /** * Nitrogen in an amide */ export function isAmide(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let flag = false; if (typeSymbol(unit, index) === Elements.N && (bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H)) === 2 ) { flag = bondToCarbonylCount(structure, unit, index) === 1; } return flag; } /** * Sulfur in a sulfonium group */ export function isSulfonium(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { return ( typeSymbol(unit, index) === Elements.S && bondCount(structure, unit, index) === 3 && bondToElementCount(structure, unit, index, Elements.H) === 0 ); } /** * Sulfur in a sulfonic acid or sulfonate group */ export function isSulfonicAcid(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { return ( typeSymbol(unit, index) === Elements.S && bondToElementCount(structure, unit, index, Elements.O) === 3 ); } /** * Sulfur in a sulfate group */ export function isSulfate(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { return ( typeSymbol(unit, index) === Elements.S && bondToElementCount(structure, unit, index, Elements.O) === 4 ); } /** * Phosphor in a phosphate group */ export function isPhosphate (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { return ( typeSymbol(unit, index) === Elements.P && bondToElementCount(structure, unit, index, Elements.O) === bondCount(structure, unit, index) ); } /** * Halogen with one bond to a carbon */ export function isHalocarbon (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { return ( isHalogen(typeSymbol(unit, index)) && bondCount(structure, unit, index) === 1 && bondToElementCount(structure, unit, index, Elements.C) === 1 ); } /** * Carbon in a carbonyl/acyl group * * TODO currently only checks intra bonds for group detection */ export function isCarbonyl(structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let flag = false; if (typeSymbol(unit, index) === Elements.C) { const { offset, edgeProps, b } = unit.bonds; for (let i = offset[index], il = offset[index + 1]; i < il; ++i) { if (edgeProps.order[i] === 2 && typeSymbol(unit, b[i] as StructureElement.UnitIndex) === Elements.O) { flag = true; break; } } } return flag; } /** * Carbon in a carboxylate group */ export function isCarboxylate (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let terminalOxygenCount = 0; if ( typeSymbol(unit, index) === Elements.C && bondToElementCount(structure, unit, index, Elements.O) === 2 && bondToElementCount(structure, unit, index, Elements.C) === 1 ) { eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => { if ( typeSymbol(unit, index) === Elements.O && bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H) === 1 ) { terminalOxygenCount += 1; } }); } return terminalOxygenCount === 2; } /** * Carbon in a guanidine group */ export function isGuanidine (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let terminalNitrogenCount = 0; if ( typeSymbol(unit, index) === Elements.C && bondCount(structure, unit, index) === 3 && bondToElementCount(structure, unit, index, Elements.N) === 3 ) { eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => { if ( bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H) === 1 ) { terminalNitrogenCount += 1; } }); } return terminalNitrogenCount === 2; } /** * Carbon in a acetamidine group */ export function isAcetamidine (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let terminalNitrogenCount = 0; if ( typeSymbol(unit, index) === Elements.C && bondCount(structure, unit, index) === 3 && bondToElementCount(structure, unit, index, Elements.N) === 2 && bondToElementCount(structure, unit, index, Elements.C) === 1 ) { eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => { if ( bondCount(structure, unit, index) - bondToElementCount(structure, unit, index, Elements.H) === 1 ) { terminalNitrogenCount += 1; } }); } return terminalNitrogenCount === 2; } const PolarElements = new Set(['N', 'O', 'S', 'F', 'CL', 'BR', 'I'] as ElementSymbol[]); export function isPolar(element: ElementSymbol) { return PolarElements.has(element); } export function hasPolarNeighbour (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let flag = false; eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => { if (isPolar(typeSymbol(unit, index))) flag = true; }); return flag; } export function hasAromaticNeighbour (structure: Structure, unit: Unit.Atomic, index: StructureElement.UnitIndex) { let flag = false; eachBondedAtom(structure, unit, index, (unit: Unit.Atomic, index: StructureElement.UnitIndex) => { if (isAromatic(unit, index)) flag = true; }); return flag; }