diff --git a/CHANGELOG.md b/CHANGELOG.md index fd3fed796..9c085073f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Note that since we don't clearly distinguish between a public and private interf - Fix polymer-gap visual coloring with cartoon theme - Add formal-charge color theme (#328) - Add more coloring options to cartoon theme +- Add `pdbx_structure_determination_methodology` mmcif field and `Model` helpers ## [v4.5.0] - 2024-07-28 diff --git a/data/cif-field-names/mmcif-field-names.csv b/data/cif-field-names/mmcif-field-names.csv index bf681d5b4..148332e38 100644 --- a/data/cif-field-names/mmcif-field-names.csv +++ b/data/cif-field-names/mmcif-field-names.csv @@ -263,6 +263,7 @@ software.version struct.entry_id struct.title struct.pdbx_descriptor +struct.pdbx_structure_determination_methodology struct_asym.id struct_asym.pdbx_blank_PDB_chainid_flag diff --git a/src/extensions/model-archive/quality-assessment/color/plddt.ts b/src/extensions/model-archive/quality-assessment/color/plddt.ts index dec33d0da..0c963a478 100644 --- a/src/extensions/model-archive/quality-assessment/color/plddt.ts +++ b/src/extensions/model-archive/quality-assessment/color/plddt.ts @@ -8,7 +8,7 @@ import { QualityAssessment, QualityAssessmentProvider } from '../prop'; import { Location } from '../../../../mol-model/location'; -import { Bond, StructureElement, Unit } from '../../../../mol-model/structure'; +import { Bond, Model, StructureElement, Unit } from '../../../../mol-model/structure'; import { ColorTheme, LocationColor } from '../../../../mol-theme/color'; import { ThemeDataContext } from '../../../../mol-theme/theme'; import { Color } from '../../../../mol-util/color'; @@ -91,7 +91,7 @@ export const PLDDTConfidenceColorThemeProvider: ColorTheme.Provider !!ctx.structure?.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT') || m.atomicConformation.B_iso_or_equiv.isDefined), + isApplicable: (ctx: ThemeDataContext) => !!ctx.structure?.models.some(m => QualityAssessment.isApplicable(m, 'pLDDT') || (m.atomicConformation.B_iso_or_equiv.isDefined && !Model.isExperimental(m))), ensureCustomProperties: { attach: async (ctx: CustomProperty.Context, data: ThemeDataContext) => { if (data.structure) { diff --git a/src/mol-io/reader/cif/schema/mmcif.ts b/src/mol-io/reader/cif/schema/mmcif.ts index 88289e5ba..3696b11f6 100644 --- a/src/mol-io/reader/cif/schema/mmcif.ts +++ b/src/mol-io/reader/cif/schema/mmcif.ts @@ -1033,6 +1033,10 @@ export const mmCIF_Schema = { * and to distinguish this structural result from others. */ title: str, + /** + * Indicates if the structure was determined using experimental, computational, or integrative methods + */ + pdbx_structure_determination_methodology: Aliased<'experimental' | 'integrative' | 'computational'>(str), /** * An automatically generated descriptor for an NDB structure or * the unstructured content of the PDB COMPND record. diff --git a/src/mol-model/structure/model/model.ts b/src/mol-model/structure/model/model.ts index 6e2386abc..a8ebee111 100644 --- a/src/mol-model/structure/model/model.ts +++ b/src/mol-model/structure/model/model.ts @@ -378,6 +378,33 @@ export namespace Model { return false; } + export function isExperimental(model: Model): boolean { + if (!MmcifFormat.is(model.sourceData)) return false; + const { db } = model.sourceData.data; + for (let i = 0; i < db.struct.pdbx_structure_determination_methodology.rowCount; i++) { + if (db.struct.pdbx_structure_determination_methodology.value(i).toLowerCase() === 'experimental') return true; + } + return false; + } + + export function isIntegrative(model: Model): boolean { + if (!MmcifFormat.is(model.sourceData)) return false; + const { db } = model.sourceData.data; + for (let i = 0; i < db.struct.pdbx_structure_determination_methodology.rowCount; i++) { + if (db.struct.pdbx_structure_determination_methodology.value(i).toLowerCase() === 'integrative') return true; + } + return false; + } + + export function isComputational(model: Model): boolean { + if (!MmcifFormat.is(model.sourceData)) return false; + const { db } = model.sourceData.data; + for (let i = 0; i < db.struct.pdbx_structure_determination_methodology.rowCount; i++) { + if (db.struct.pdbx_structure_determination_methodology.value(i).toLowerCase() === 'computational') return true; + } + return false; + } + export function hasXrayMap(model: Model): boolean { if (!MmcifFormat.is(model.sourceData)) return false; // Check exprimental method to exclude models solved with