prop.ts 5.6 KB

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