diff --git a/src/mol-model-formats/structure/mmcif/parser.ts b/src/mol-model-formats/structure/mmcif/parser.ts index 0721e70eb72d970d603ce0357c24d7110db514b8..f797e919cdb4f207224669ff11d095c9ace24f7f 100644 --- a/src/mol-model-formats/structure/mmcif/parser.ts +++ b/src/mol-model-formats/structure/mmcif/parser.ts @@ -12,7 +12,7 @@ import { Tensor, Vec3 } from '../../../mol-math/linear-algebra'; import { RuntimeContext } from '../../../mol-task'; import UUID from '../../../mol-util/uuid'; import { Model } from '../../../mol-model/structure/model/model'; -import { Entities } from '../../../mol-model/structure/model/properties/common'; +import { Entities, ChemicalComponent, MissingResidue } from '../../../mol-model/structure/model/properties/common'; import { CustomProperties } from '../../../mol-model/structure'; import { ModelSymmetry } from '../../../mol-model/structure/model/properties/symmetry'; import { createAssemblies } from './assembly'; @@ -23,7 +23,6 @@ import { getSecondaryStructure } from './secondary-structure'; import { getSequence } from './sequence'; import { sortAtomSite } from './sort'; import { StructConn } from './bonds/struct_conn'; -import { ChemicalComponent } from '../../../mol-model/structure/model/properties/chemical-component'; import { getMoleculeType, MoleculeType, getEntityType } from '../../../mol-model/structure/model/types'; import { ModelFormat } from '../format'; import { SaccharideComponentMap, SaccharideComponent, SaccharidesSnfgMap, SaccharideCompIdMap, UnknownSaccharideComponent } from '../../../mol-model/structure/structure/carbohydrates/constants'; @@ -98,14 +97,36 @@ function getModifiedResidueNameMap(format: mmCIF_Format): Model['properties']['m return { parentId, details }; } +function getMissingResidues(format: mmCIF_Format): Model['properties']['missingResidues'] { + const map = new Map<string, MissingResidue>(); + const c = format.data.pdbx_unobs_or_zero_occ_residues + + const getKey = (model_num: number, asym_id: string, seq_id: number) => { + return `${model_num}|${asym_id}|${seq_id}` + } + + for (let i = 0, il = c._rowCount; i < il; ++i) { + const key = getKey(c.PDB_model_num.value(i), c.label_asym_id.value(i), c.label_seq_id.value(i)) + map.set(key, { polymer_flag: c.polymer_flag.value(i), occupancy_flag: c.occupancy_flag.value(i) }) + } + + return { + has: (model_num: number, asym_id: string, seq_id: number) => { + return map.has(getKey(model_num, asym_id, seq_id)) + }, + get: (model_num: number, asym_id: string, seq_id: number) => { + return map.get(getKey(model_num, asym_id, seq_id)) + }, + size: map.size + } +} + function getChemicalComponentMap(format: mmCIF_Format): Model['properties']['chemicalComponentMap'] { const map = new Map<string, ChemicalComponent>(); const { chem_comp } = format.data - if (chem_comp._rowCount > 0) { - const { id } = format.data.chem_comp - for (let i = 0, il = id.rowCount; i < il; ++i) { - map.set(id.value(i), Table.getRow(format.data.chem_comp, i)) - } + const { id } = chem_comp + for (let i = 0, il = id.rowCount; i < il; ++i) { + map.set(id.value(i), Table.getRow(chem_comp, i)) } return map } @@ -158,6 +179,7 @@ const getUniqueComponentNames = memoize1((format: mmCIF_Format) => { export interface FormatData { modifiedResidues: Model['properties']['modifiedResidues'] + missingResidues: Model['properties']['missingResidues'] chemicalComponentMap: Model['properties']['chemicalComponentMap'] saccharideComponentMap: Model['properties']['saccharideComponentMap'] } @@ -165,6 +187,7 @@ export interface FormatData { function getFormatData(format: mmCIF_Format): FormatData { return { modifiedResidues: getModifiedResidueNameMap(format), + missingResidues: getMissingResidues(format), chemicalComponentMap: getChemicalComponentMap(format), saccharideComponentMap: getSaccharideComponentMap(format) } @@ -172,11 +195,12 @@ function getFormatData(format: mmCIF_Format): FormatData { function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, sourceIndex: Column<number>, entities: Entities, formatData: FormatData, previous?: Model): Model { const atomic = getAtomicHierarchyAndConformation(atom_site, sourceIndex, entities, formatData, previous); + const modelNum = atom_site.pdbx_PDB_model_num.value(0) if (previous && atomic.sameAsPrevious) { return { ...previous, id: UUID.create22(), - modelNum: atom_site.pdbx_PDB_model_num.value(0), + modelNum, atomicConformation: atomic.conformation, _dynamicPropertyData: Object.create(null) }; @@ -192,7 +216,7 @@ function createStandardModel(format: mmCIF_Format, atom_site: AtomSite, sourceIn label, entry: label, sourceData: format, - modelNum: atom_site.pdbx_PDB_model_num.value(0), + modelNum, entities, symmetry: getSymmetry(format), sequence: getSequence(format.data, entities, atomic.hierarchy, formatData.modifiedResidues.parentId), diff --git a/src/mol-model/structure/model/model.ts b/src/mol-model/structure/model/model.ts index cd660879e8b16b92976667ff3db3f08998281709..22d1ae04e11f64f66543d5d8b0c134c875afe6bb 100644 --- a/src/mol-model/structure/model/model.ts +++ b/src/mol-model/structure/model/model.ts @@ -10,12 +10,11 @@ import StructureSequence from './properties/sequence'; import { AtomicHierarchy, AtomicConformation } from './properties/atomic'; import { ModelSymmetry } from './properties/symmetry'; import { CoarseHierarchy, CoarseConformation } from './properties/coarse'; -import { Entities } from './properties/common'; +import { Entities, ChemicalComponentMap, MissingResidues } from './properties/common'; import { CustomProperties } from '../common/custom-property'; import { SecondaryStructure } from './properties/seconday-structure'; import { SaccharideComponentMap } from '../structure/carbohydrates/constants'; import { ModelFormat } from '../../../mol-model-formats/structure/format'; -import { ChemicalComponentMap } from './properties/chemical-component'; /** * Interface to the "source data" of the molecule. @@ -49,6 +48,8 @@ export interface Model extends Readonly<{ parentId: ReadonlyMap<string, string>, details: ReadonlyMap<string, string> }>, + /** map that holds details about unobserved or zero occurrence residues */ + readonly missingResidues: MissingResidues, /** maps residue name to `ChemicalComponent` data */ readonly chemicalComponentMap: ChemicalComponentMap /** maps residue name to `SaccharideComponent` data */ diff --git a/src/mol-model/structure/model/properties/chemical-component.ts b/src/mol-model/structure/model/properties/chemical-component.ts deleted file mode 100644 index bc31df3247cb888ddb504e5a414ca111a3858d99..0000000000000000000000000000000000000000 --- a/src/mol-model/structure/model/properties/chemical-component.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. - * - * @author Alexander Rose <alexander.rose@weirdbyte.de> - */ - -import { mmCIF_Schema } from '../../../../mol-io/reader/cif/schema/mmcif'; -import { Table } from '../../../../mol-data/db'; - -export type ChemicalComponent = Table.Row<mmCIF_Schema['chem_comp']> -export type ChemicalComponentMap = ReadonlyMap<string, ChemicalComponent> - -// TODO add data for common chemical components \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/common.ts b/src/mol-model/structure/model/properties/common.ts index 8355c9dceddafd302dca593b5adee128b050d30b..577367b67163a6a931de616b0beb58f66c292eb8 100644 --- a/src/mol-model/structure/model/properties/common.ts +++ b/src/mol-model/structure/model/properties/common.ts @@ -1,13 +1,28 @@ /** - * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info. * + * @author Alexander Rose <alexander.rose@weirdbyte.de> * @author David Sehnal <david.sehnal@gmail.com> */ -import { mmCIF_Database as mmCIF } from '../../../../mol-io/reader/cif/schema/mmcif' +import { mmCIF_Database, mmCIF_Schema } from '../../../../mol-io/reader/cif/schema/mmcif' +import { Table } from '../../../../mol-data/db'; import { EntityIndex } from '../indexing'; export interface Entities { - data: mmCIF['entity'], + data: mmCIF_Database['entity'], getEntityIndex(id: string): EntityIndex +} + +export type ChemicalComponent = Table.Row<mmCIF_Schema['chem_comp']> +export type ChemicalComponentMap = ReadonlyMap<string, ChemicalComponent> + +export type MissingResidue = Table.Row<Pick< + mmCIF_Schema['pdbx_unobs_or_zero_occ_residues'], + 'polymer_flag' | 'occupancy_flag'> +> +export interface MissingResidues { + has(model_num: number, asym_id: string, seq_id: number): boolean + get(model_num: number, asym_id: string, seq_id: number): MissingResidue | undefined + readonly size: number } \ No newline at end of file diff --git a/src/mol-model/structure/model/properties/utils/atomic-derived.ts b/src/mol-model/structure/model/properties/utils/atomic-derived.ts index 11706d5ada50c1cab3eb8459e681e444d347908d..ae82751c4c6740d05e54a77e0efe7c09acce1a44 100644 --- a/src/mol-model/structure/model/properties/utils/atomic-derived.ts +++ b/src/mol-model/structure/model/properties/utils/atomic-derived.ts @@ -5,11 +5,11 @@ */ import { AtomicData } from '../atomic'; -import { ChemicalComponentMap } from '../chemical-component'; import { AtomicIndex, AtomicDerivedData } from '../atomic/hierarchy'; import { ElementIndex, ResidueIndex } from '../../indexing'; import { MoleculeType, getMoleculeType, getComponentType } from '../../types'; import { getAtomIdForAtomRole } from '../../../../../mol-model/structure/util'; +import { ChemicalComponentMap } from '../common'; export function getAtomicDerivedData(data: AtomicData, index: AtomicIndex, chemicalComponentMap: ChemicalComponentMap): AtomicDerivedData { const { label_comp_id, _rowCount: n } = data.residues diff --git a/src/mol-model/structure/model/properties/utils/coarse-ranges.ts b/src/mol-model/structure/model/properties/utils/coarse-ranges.ts index e7fb45928f8fdddfced1307ac67ef670bd8832fc..74c5f432ea7e9ad99aa7f6c39aa7e11f712e6eba 100644 --- a/src/mol-model/structure/model/properties/utils/coarse-ranges.ts +++ b/src/mol-model/structure/model/properties/utils/coarse-ranges.ts @@ -7,8 +7,8 @@ import { CoarseRanges, CoarseElementData } from '../coarse/hierarchy'; import { Segmentation, Interval } from '../../../../../mol-data/int'; import SortedRanges from '../../../../../mol-data/int/sorted-ranges'; -import { ChemicalComponent } from '../chemical-component'; import { ElementIndex } from '../../indexing'; +import { ChemicalComponent } from '../common'; // TODO assumes all coarse elements are part of a polymer // TODO add gaps at the ends of the chains by comparing to the polymer sequence data diff --git a/src/mol-plugin/ui/sequence/polymer.ts b/src/mol-plugin/ui/sequence/polymer.ts index a6302fd24498601fb5dc8924dc91be8bd6c2f8c8..03b1f60d09c59a3e7d8886b3013733bd950ebb56 100644 --- a/src/mol-plugin/ui/sequence/polymer.ts +++ b/src/mol-plugin/ui/sequence/polymer.ts @@ -9,13 +9,18 @@ import { SequenceWrapper } from './util'; import { OrderedSet, Interval } from '../../../mol-data/int'; import { Loci } from '../../../mol-model/loci'; import { Sequence } from '../../../mol-model/sequence'; -import { Color } from '../../../mol-util/color'; +import { MissingResidues } from '../../../mol-model/structure/model/properties/common'; +import { ColorNames } from '../../../mol-util/color/tables'; export type StructureUnit = { structure: Structure, unit: Unit } export class PolymerSequenceWrapper extends SequenceWrapper<StructureUnit> { private readonly location: StructureElement private readonly sequence: Sequence + private readonly missing: MissingResidues + + private readonly modelNum: number + private readonly asymId: string seqId(i: number) { return this.sequence.offset + i + 1 @@ -24,7 +29,9 @@ export class PolymerSequenceWrapper extends SequenceWrapper<StructureUnit> { return this.sequence.sequence[i] } residueColor(i: number) { - return Color(0) + return this.missing.has(this.modelNum, this.asymId, this.seqId(i)) + ? ColorNames.grey + : ColorNames.black } eachResidue(loci: Loci, apply: (interval: Interval) => boolean) { @@ -69,6 +76,10 @@ export class PolymerSequenceWrapper extends SequenceWrapper<StructureUnit> { this.sequence = sequence this.location = StructureElement.create() + this.missing = data.unit.model.properties.missingResidues + + this.modelNum = data.unit.model.modelNum + this.asymId = SP.chain.label_asym_id(l) } }