prop.ts 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /**
  2. * Copyright (c) 2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  5. * @author David Sehnal <david.sehnal@gmail.com>
  6. */
  7. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  8. import { Unit } from '../../../mol-model/structure';
  9. import { CustomProperty } from '../../../mol-model-props/common/custom-property';
  10. import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property';
  11. import { Model, ResidueIndex } from '../../../mol-model/structure/model';
  12. import { QuerySymbolRuntime } from '../../../mol-script/runtime/query/compiler';
  13. import { CustomPropSymbol } from '../../../mol-script/language/symbol';
  14. import { Type } from '../../../mol-script/language/type';
  15. import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
  16. import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
  17. import { AtomicIndex } from '../../../mol-model/structure/model/properties/atomic';
  18. export { QualityAssessment };
  19. interface QualityAssessment {
  20. localMetrics: Map<string, Map<ResidueIndex, number>>
  21. pLDDT?: Map<ResidueIndex, number>
  22. qmean?: Map<ResidueIndex, number>
  23. }
  24. namespace QualityAssessment {
  25. const Empty = {
  26. value: {
  27. localMetrics: new Map()
  28. }
  29. };
  30. export function isApplicable(model?: Model, localMetricName?: 'pLDDT' | 'qmean'): boolean {
  31. if (!model || !MmcifFormat.is(model.sourceData)) return false;
  32. const { db } = model.sourceData.data;
  33. const hasLocalMetric = (
  34. db.ma_qa_metric.id.isDefined &&
  35. db.ma_qa_metric_local.ordinal_id.isDefined
  36. );
  37. if (localMetricName && hasLocalMetric) {
  38. for (let i = 0, il = db.ma_qa_metric._rowCount; i < il; i++) {
  39. if (db.ma_qa_metric.mode.value(i) !== 'local') continue;
  40. if (localMetricName === db.ma_qa_metric.name.value(i)) return true;
  41. }
  42. return false;
  43. } else {
  44. return hasLocalMetric;
  45. }
  46. }
  47. export async function obtain(ctx: CustomProperty.Context, model: Model, props: QualityAssessmentProps): Promise<CustomProperty.Data<QualityAssessment>> {
  48. if (!model || !MmcifFormat.is(model.sourceData)) return Empty;
  49. const { ma_qa_metric, ma_qa_metric_local } = model.sourceData.data.db;
  50. const { model_id, label_asym_id, label_seq_id, metric_id, metric_value } = ma_qa_metric_local;
  51. const { index } = model.atomicHierarchy;
  52. // for simplicity we assume names in ma_qa_metric for mode 'local' are unique
  53. const localMetrics = new Map<string, Map<ResidueIndex, number>>();
  54. const localNames = new Map<number, string>();
  55. for (let i = 0, il = ma_qa_metric._rowCount; i < il; i++) {
  56. if (ma_qa_metric.mode.value(i) !== 'local') continue;
  57. const name = ma_qa_metric.name.value(i);
  58. if (localMetrics.has(name)) {
  59. console.warn(`local ma_qa_metric with name '${name}' already added`);
  60. continue;
  61. }
  62. localMetrics.set(name, new Map());
  63. localNames.set(ma_qa_metric.id.value(i), name);
  64. }
  65. const residueKey: AtomicIndex.ResidueLabelKey = {
  66. label_entity_id: '',
  67. label_asym_id: '',
  68. label_seq_id: 0,
  69. pdbx_PDB_ins_code: undefined,
  70. };
  71. for (let i = 0, il = ma_qa_metric_local._rowCount; i < il; i++) {
  72. if (model_id.value(i) !== model.modelNum) continue;
  73. const labelAsymId = label_asym_id.value(i);
  74. const entityIndex = index.findEntity(labelAsymId);
  75. residueKey.label_entity_id = model.entities.data.id.value(entityIndex);
  76. residueKey.label_asym_id = labelAsymId;
  77. residueKey.label_seq_id = label_seq_id.value(i);
  78. const rI = index.findResidueLabel(residueKey);
  79. if (rI >= 0) {
  80. const name = localNames.get(metric_id.value(i))!;
  81. localMetrics.get(name)!.set(rI, metric_value.value(i));
  82. }
  83. }
  84. return {
  85. value: {
  86. localMetrics,
  87. pLDDT: localMetrics.get('pLDDT'),
  88. qmean: localMetrics.get('qmean'),
  89. }
  90. };
  91. }
  92. export const symbols = {
  93. pLDDT: QuerySymbolRuntime.Dynamic(CustomPropSymbol('ma', 'quality-assessment.pLDDT', Type.Num),
  94. ctx => {
  95. const { unit, element } = ctx.element;
  96. if (!Unit.isAtomic(unit)) return -1;
  97. const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
  98. return qualityAssessment?.pLDDT?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
  99. }
  100. ),
  101. qmean: QuerySymbolRuntime.Dynamic(CustomPropSymbol('ma', 'quality-assessment.qmean', Type.Num),
  102. ctx => {
  103. const { unit, element } = ctx.element;
  104. if (!Unit.isAtomic(unit)) return -1;
  105. const qualityAssessment = QualityAssessmentProvider.get(unit.model).value;
  106. return qualityAssessment?.qmean?.get(unit.model.atomicHierarchy.residueAtomSegments.index[element]) ?? -1;
  107. }
  108. ),
  109. };
  110. }
  111. export const QualityAssessmentParams = { };
  112. export type QualityAssessmentParams = typeof QualityAssessmentParams
  113. export type QualityAssessmentProps = PD.Values<QualityAssessmentParams>
  114. export const QualityAssessmentProvider: CustomModelProperty.Provider<QualityAssessmentParams, QualityAssessment> = CustomModelProperty.createProvider({
  115. label: 'QualityAssessment',
  116. descriptor: CustomPropertyDescriptor({
  117. name: 'ma_quality_assessment',
  118. symbols: QualityAssessment.symbols
  119. }),
  120. type: 'static',
  121. defaultParams: QualityAssessmentParams,
  122. getParams: (data: Model) => QualityAssessmentParams,
  123. isApplicable: (data: Model) => QualityAssessment.isApplicable(data),
  124. obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<QualityAssessmentProps>) => {
  125. const p = { ...PD.getDefaultValues(QualityAssessmentParams), ...props };
  126. return await QualityAssessment.obtain(ctx, data, p);
  127. }
  128. });