ソースを参照

Factor out common Dnatco code

Michal Malý 2 年 前
コミット
d29cc85439

+ 1 - 0
CHANGELOG.md

@@ -29,6 +29,7 @@ Note that since we don't clearly distinguish between a public and private interf
 - Add `.getCenter` and `.center` to `Camera`
 - Add support to dim unmarked groups
 - Add support for marker edge strength
+- Factor out common code in `Dnatco` extension
 
 ## [v3.28.0] - 2022-12-20
 

+ 219 - 0
src/extensions/dnatco/color.ts

@@ -0,0 +1,219 @@
+/**
+ * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Michal Malý <michal.maly@ibt.cas.cz>
+ * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
+ */
+
+import { Color, ColorMap } from '../../mol-util/color';
+
+export const DefaultNtCClassColors = {
+    A: 0xFFC1C1,
+    B: 0xC8CFFF,
+    BII: 0x0059DA,
+    miB: 0x3BE8FB,
+    Z: 0x01F60E,
+    IC: 0xFA5CFB,
+    OPN: 0xE90000,
+    SYN: 0xFFFF01,
+    N: 0xF2F2F2,
+};
+export const ErrorColor = Color(0xFFA10A);
+
+export const NtCColors = ColorMap({
+    NANT_Upr: DefaultNtCClassColors.N,
+    NANT_Lwr: DefaultNtCClassColors.N,
+    AA00_Upr: DefaultNtCClassColors.A,
+    AA00_Lwr: DefaultNtCClassColors.A,
+    AA02_Upr: DefaultNtCClassColors.A,
+    AA02_Lwr: DefaultNtCClassColors.A,
+    AA03_Upr: DefaultNtCClassColors.A,
+    AA03_Lwr: DefaultNtCClassColors.A,
+    AA04_Upr: DefaultNtCClassColors.A,
+    AA04_Lwr: DefaultNtCClassColors.A,
+    AA08_Upr: DefaultNtCClassColors.A,
+    AA08_Lwr: DefaultNtCClassColors.A,
+    AA09_Upr: DefaultNtCClassColors.A,
+    AA09_Lwr: DefaultNtCClassColors.A,
+    AA01_Upr: DefaultNtCClassColors.A,
+    AA01_Lwr: DefaultNtCClassColors.A,
+    AA05_Upr: DefaultNtCClassColors.A,
+    AA05_Lwr: DefaultNtCClassColors.A,
+    AA06_Upr: DefaultNtCClassColors.A,
+    AA06_Lwr: DefaultNtCClassColors.A,
+    AA10_Upr: DefaultNtCClassColors.A,
+    AA10_Lwr: DefaultNtCClassColors.A,
+    AA11_Upr: DefaultNtCClassColors.A,
+    AA11_Lwr: DefaultNtCClassColors.A,
+    AA07_Upr: DefaultNtCClassColors.A,
+    AA07_Lwr: DefaultNtCClassColors.A,
+    AA12_Upr: DefaultNtCClassColors.A,
+    AA12_Lwr: DefaultNtCClassColors.A,
+    AA13_Upr: DefaultNtCClassColors.A,
+    AA13_Lwr: DefaultNtCClassColors.A,
+    AB01_Upr: DefaultNtCClassColors.A,
+    AB01_Lwr: DefaultNtCClassColors.B,
+    AB02_Upr: DefaultNtCClassColors.A,
+    AB02_Lwr: DefaultNtCClassColors.B,
+    AB03_Upr: DefaultNtCClassColors.A,
+    AB03_Lwr: DefaultNtCClassColors.B,
+    AB04_Upr: DefaultNtCClassColors.A,
+    AB04_Lwr: DefaultNtCClassColors.B,
+    AB05_Upr: DefaultNtCClassColors.A,
+    AB05_Lwr: DefaultNtCClassColors.B,
+    BA01_Upr: DefaultNtCClassColors.B,
+    BA01_Lwr: DefaultNtCClassColors.A,
+    BA05_Upr: DefaultNtCClassColors.B,
+    BA05_Lwr: DefaultNtCClassColors.A,
+    BA09_Upr: DefaultNtCClassColors.B,
+    BA09_Lwr: DefaultNtCClassColors.A,
+    BA08_Upr: DefaultNtCClassColors.BII,
+    BA08_Lwr: DefaultNtCClassColors.A,
+    BA10_Upr: DefaultNtCClassColors.B,
+    BA10_Lwr: DefaultNtCClassColors.A,
+    BA13_Upr: DefaultNtCClassColors.BII,
+    BA13_Lwr: DefaultNtCClassColors.A,
+    BA16_Upr: DefaultNtCClassColors.BII,
+    BA16_Lwr: DefaultNtCClassColors.A,
+    BA17_Upr: DefaultNtCClassColors.BII,
+    BA17_Lwr: DefaultNtCClassColors.A,
+    BB00_Upr: DefaultNtCClassColors.B,
+    BB00_Lwr: DefaultNtCClassColors.B,
+    BB01_Upr: DefaultNtCClassColors.B,
+    BB01_Lwr: DefaultNtCClassColors.B,
+    BB17_Upr: DefaultNtCClassColors.B,
+    BB17_Lwr: DefaultNtCClassColors.B,
+    BB02_Upr: DefaultNtCClassColors.B,
+    BB02_Lwr: DefaultNtCClassColors.B,
+    BB03_Upr: DefaultNtCClassColors.B,
+    BB03_Lwr: DefaultNtCClassColors.B,
+    BB11_Upr: DefaultNtCClassColors.B,
+    BB11_Lwr: DefaultNtCClassColors.B,
+    BB16_Upr: DefaultNtCClassColors.B,
+    BB16_Lwr: DefaultNtCClassColors.B,
+    BB04_Upr: DefaultNtCClassColors.B,
+    BB04_Lwr: DefaultNtCClassColors.BII,
+    BB05_Upr: DefaultNtCClassColors.B,
+    BB05_Lwr: DefaultNtCClassColors.BII,
+    BB07_Upr: DefaultNtCClassColors.BII,
+    BB07_Lwr: DefaultNtCClassColors.BII,
+    BB08_Upr: DefaultNtCClassColors.BII,
+    BB08_Lwr: DefaultNtCClassColors.BII,
+    BB10_Upr: DefaultNtCClassColors.miB,
+    BB10_Lwr: DefaultNtCClassColors.miB,
+    BB12_Upr: DefaultNtCClassColors.miB,
+    BB12_Lwr: DefaultNtCClassColors.miB,
+    BB13_Upr: DefaultNtCClassColors.miB,
+    BB13_Lwr: DefaultNtCClassColors.miB,
+    BB14_Upr: DefaultNtCClassColors.miB,
+    BB14_Lwr: DefaultNtCClassColors.miB,
+    BB15_Upr: DefaultNtCClassColors.miB,
+    BB15_Lwr: DefaultNtCClassColors.miB,
+    BB20_Upr: DefaultNtCClassColors.miB,
+    BB20_Lwr: DefaultNtCClassColors.miB,
+    IC01_Upr: DefaultNtCClassColors.IC,
+    IC01_Lwr: DefaultNtCClassColors.IC,
+    IC02_Upr: DefaultNtCClassColors.IC,
+    IC02_Lwr: DefaultNtCClassColors.IC,
+    IC03_Upr: DefaultNtCClassColors.IC,
+    IC03_Lwr: DefaultNtCClassColors.IC,
+    IC04_Upr: DefaultNtCClassColors.IC,
+    IC04_Lwr: DefaultNtCClassColors.IC,
+    IC05_Upr: DefaultNtCClassColors.IC,
+    IC05_Lwr: DefaultNtCClassColors.IC,
+    IC06_Upr: DefaultNtCClassColors.IC,
+    IC06_Lwr: DefaultNtCClassColors.IC,
+    IC07_Upr: DefaultNtCClassColors.IC,
+    IC07_Lwr: DefaultNtCClassColors.IC,
+    OP01_Upr: DefaultNtCClassColors.OPN,
+    OP01_Lwr: DefaultNtCClassColors.OPN,
+    OP02_Upr: DefaultNtCClassColors.OPN,
+    OP02_Lwr: DefaultNtCClassColors.OPN,
+    OP03_Upr: DefaultNtCClassColors.OPN,
+    OP03_Lwr: DefaultNtCClassColors.OPN,
+    OP04_Upr: DefaultNtCClassColors.OPN,
+    OP04_Lwr: DefaultNtCClassColors.OPN,
+    OP05_Upr: DefaultNtCClassColors.OPN,
+    OP05_Lwr: DefaultNtCClassColors.OPN,
+    OP06_Upr: DefaultNtCClassColors.OPN,
+    OP06_Lwr: DefaultNtCClassColors.OPN,
+    OP07_Upr: DefaultNtCClassColors.OPN,
+    OP07_Lwr: DefaultNtCClassColors.OPN,
+    OP08_Upr: DefaultNtCClassColors.OPN,
+    OP08_Lwr: DefaultNtCClassColors.OPN,
+    OP09_Upr: DefaultNtCClassColors.OPN,
+    OP09_Lwr: DefaultNtCClassColors.OPN,
+    OP10_Upr: DefaultNtCClassColors.OPN,
+    OP10_Lwr: DefaultNtCClassColors.OPN,
+    OP11_Upr: DefaultNtCClassColors.OPN,
+    OP11_Lwr: DefaultNtCClassColors.OPN,
+    OP12_Upr: DefaultNtCClassColors.OPN,
+    OP12_Lwr: DefaultNtCClassColors.OPN,
+    OP13_Upr: DefaultNtCClassColors.OPN,
+    OP13_Lwr: DefaultNtCClassColors.OPN,
+    OP14_Upr: DefaultNtCClassColors.OPN,
+    OP14_Lwr: DefaultNtCClassColors.OPN,
+    OP15_Upr: DefaultNtCClassColors.OPN,
+    OP15_Lwr: DefaultNtCClassColors.OPN,
+    OP16_Upr: DefaultNtCClassColors.OPN,
+    OP16_Lwr: DefaultNtCClassColors.OPN,
+    OP17_Upr: DefaultNtCClassColors.OPN,
+    OP17_Lwr: DefaultNtCClassColors.OPN,
+    OP18_Upr: DefaultNtCClassColors.OPN,
+    OP18_Lwr: DefaultNtCClassColors.OPN,
+    OP19_Upr: DefaultNtCClassColors.OPN,
+    OP19_Lwr: DefaultNtCClassColors.OPN,
+    OP20_Upr: DefaultNtCClassColors.OPN,
+    OP20_Lwr: DefaultNtCClassColors.OPN,
+    OP21_Upr: DefaultNtCClassColors.OPN,
+    OP21_Lwr: DefaultNtCClassColors.OPN,
+    OP22_Upr: DefaultNtCClassColors.OPN,
+    OP22_Lwr: DefaultNtCClassColors.OPN,
+    OP23_Upr: DefaultNtCClassColors.OPN,
+    OP23_Lwr: DefaultNtCClassColors.OPN,
+    OP24_Upr: DefaultNtCClassColors.OPN,
+    OP24_Lwr: DefaultNtCClassColors.OPN,
+    OP25_Upr: DefaultNtCClassColors.OPN,
+    OP25_Lwr: DefaultNtCClassColors.OPN,
+    OP26_Upr: DefaultNtCClassColors.OPN,
+    OP26_Lwr: DefaultNtCClassColors.OPN,
+    OP27_Upr: DefaultNtCClassColors.OPN,
+    OP27_Lwr: DefaultNtCClassColors.OPN,
+    OP28_Upr: DefaultNtCClassColors.OPN,
+    OP28_Lwr: DefaultNtCClassColors.OPN,
+    OP29_Upr: DefaultNtCClassColors.OPN,
+    OP29_Lwr: DefaultNtCClassColors.OPN,
+    OP30_Upr: DefaultNtCClassColors.OPN,
+    OP30_Lwr: DefaultNtCClassColors.OPN,
+    OP31_Upr: DefaultNtCClassColors.OPN,
+    OP31_Lwr: DefaultNtCClassColors.OPN,
+    OPS1_Upr: DefaultNtCClassColors.OPN,
+    OPS1_Lwr: DefaultNtCClassColors.OPN,
+    OP1S_Upr: DefaultNtCClassColors.OPN,
+    OP1S_Lwr: DefaultNtCClassColors.SYN,
+    AAS1_Upr: DefaultNtCClassColors.SYN,
+    AAS1_Lwr: DefaultNtCClassColors.A,
+    AB1S_Upr: DefaultNtCClassColors.A,
+    AB1S_Lwr: DefaultNtCClassColors.SYN,
+    AB2S_Upr: DefaultNtCClassColors.A,
+    AB2S_Lwr: DefaultNtCClassColors.SYN,
+    BB1S_Upr: DefaultNtCClassColors.B,
+    BB1S_Lwr: DefaultNtCClassColors.SYN,
+    BB2S_Upr: DefaultNtCClassColors.B,
+    BB2S_Lwr: DefaultNtCClassColors.SYN,
+    BBS1_Upr: DefaultNtCClassColors.SYN,
+    BBS1_Lwr: DefaultNtCClassColors.B,
+    ZZ01_Upr: DefaultNtCClassColors.Z,
+    ZZ01_Lwr: DefaultNtCClassColors.Z,
+    ZZ02_Upr: DefaultNtCClassColors.Z,
+    ZZ02_Lwr: DefaultNtCClassColors.Z,
+    ZZ1S_Upr: DefaultNtCClassColors.Z,
+    ZZ1S_Lwr: DefaultNtCClassColors.SYN,
+    ZZ2S_Upr: DefaultNtCClassColors.Z,
+    ZZ2S_Lwr: DefaultNtCClassColors.SYN,
+    ZZS1_Upr: DefaultNtCClassColors.SYN,
+    ZZS1_Lwr: DefaultNtCClassColors.Z,
+    ZZS2_Upr: DefaultNtCClassColors.SYN,
+    ZZS2_Lwr: DefaultNtCClassColors.Z,
+});
+

+ 6 - 5
src/extensions/dnatco/confal-pyramids/behavior.ts

@@ -6,9 +6,10 @@
  */
 
 import { ConfalPyramidsColorThemeProvider } from './color';
-import { ConfalPyramids, ConfalPyramidsProvider } from './property';
+import { ConfalPyramidsProvider } from './property';
 import { ConfalPyramidsRepresentationProvider } from './representation';
-import { ConfalPyramidsTypes } from './types';
+import { Dnatco } from '../property';
+import { DnatcoTypes } from '../types';
 import { PluginBehavior } from '../../../mol-plugin/behavior/behavior';
 import { StructureRepresentationPresetProvider, PresetStructureRepresentations } from '../../../mol-plugin-state/builder/structure/representation-preset';
 import { StateObjectRef } from '../../../mol-state';
@@ -22,7 +23,7 @@ export const DnatcoConfalPyramidsPreset = StructureRepresentationPresetProvider(
         description: 'Schematic depiction of conformer class and confal value.',
     },
     isApplicable(a) {
-        return a.data.models.length >= 1 && a.data.models.some(m => ConfalPyramids.isApplicable(m));
+        return a.data.models.length >= 1 && a.data.models.some(m => Dnatco.isApplicable(m));
     },
     params: () => StructureRepresentationPresetProvider.CommonParams,
     async apply(ref, params, plugin) {
@@ -90,8 +91,8 @@ export const DnatcoConfalPyramids = PluginBehavior.create<{ autoAttach: boolean,
     })
 });
 
-export function confalPyramidLabel(halfPyramid: ConfalPyramidsTypes.HalfPyramid) {
-    const { step } = halfPyramid;
+export function confalPyramidLabel(halfStep: DnatcoTypes.HalfStep) {
+    const { step } = halfStep;
     return `
         <b>${step.auth_asym_id_1}</b> |
         <b>${step.label_comp_id_1} ${step.auth_seq_id_1}${step.PDB_ins_code_1}${step.label_alt_id_1.length > 0 ? ` (alt ${step.label_alt_id_1})` : ''}

+ 5 - 211
src/extensions/dnatco/confal-pyramids/color.ts

@@ -5,8 +5,10 @@
  * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
  */
 
-import { ConfalPyramids, ConfalPyramidsProvider } from './property';
+import { ErrorColor, NtCColors } from '../color';
+import { ConfalPyramidsProvider } from './property';
 import { ConfalPyramidsTypes as CPT } from './types';
+import { Dnatco } from '../property';
 import { Location } from '../../../mol-model/location';
 import { CustomProperty } from '../../../mol-model-props/common/custom-property';
 import { ColorTheme } from '../../../mol-theme/color';
@@ -19,215 +21,7 @@ import { ObjectKeys } from '../../../mol-util/type-helpers';
 
 const Description = 'Assigns colors to confal pyramids';
 
-const DefaultClassColors = {
-    A: 0xFFC1C1,
-    B: 0xC8CFFF,
-    BII: 0x0059DA,
-    miB: 0x3BE8FB,
-    Z: 0x01F60E,
-    IC: 0xFA5CFB,
-    OPN: 0xE90000,
-    SYN: 0xFFFF01,
-    N: 0xF2F2F2,
-};
-const ErrorColor = Color(0xFFA10A);
-
-const PyramidsColors = ColorMap({
-    NANT_Upr: DefaultClassColors.N,
-    NANT_Lwr: DefaultClassColors.N,
-    AA00_Upr: DefaultClassColors.A,
-    AA00_Lwr: DefaultClassColors.A,
-    AA02_Upr: DefaultClassColors.A,
-    AA02_Lwr: DefaultClassColors.A,
-    AA03_Upr: DefaultClassColors.A,
-    AA03_Lwr: DefaultClassColors.A,
-    AA04_Upr: DefaultClassColors.A,
-    AA04_Lwr: DefaultClassColors.A,
-    AA08_Upr: DefaultClassColors.A,
-    AA08_Lwr: DefaultClassColors.A,
-    AA09_Upr: DefaultClassColors.A,
-    AA09_Lwr: DefaultClassColors.A,
-    AA01_Upr: DefaultClassColors.A,
-    AA01_Lwr: DefaultClassColors.A,
-    AA05_Upr: DefaultClassColors.A,
-    AA05_Lwr: DefaultClassColors.A,
-    AA06_Upr: DefaultClassColors.A,
-    AA06_Lwr: DefaultClassColors.A,
-    AA10_Upr: DefaultClassColors.A,
-    AA10_Lwr: DefaultClassColors.A,
-    AA11_Upr: DefaultClassColors.A,
-    AA11_Lwr: DefaultClassColors.A,
-    AA07_Upr: DefaultClassColors.A,
-    AA07_Lwr: DefaultClassColors.A,
-    AA12_Upr: DefaultClassColors.A,
-    AA12_Lwr: DefaultClassColors.A,
-    AA13_Upr: DefaultClassColors.A,
-    AA13_Lwr: DefaultClassColors.A,
-    AB01_Upr: DefaultClassColors.A,
-    AB01_Lwr: DefaultClassColors.B,
-    AB02_Upr: DefaultClassColors.A,
-    AB02_Lwr: DefaultClassColors.B,
-    AB03_Upr: DefaultClassColors.A,
-    AB03_Lwr: DefaultClassColors.B,
-    AB04_Upr: DefaultClassColors.A,
-    AB04_Lwr: DefaultClassColors.B,
-    AB05_Upr: DefaultClassColors.A,
-    AB05_Lwr: DefaultClassColors.B,
-    BA01_Upr: DefaultClassColors.B,
-    BA01_Lwr: DefaultClassColors.A,
-    BA05_Upr: DefaultClassColors.B,
-    BA05_Lwr: DefaultClassColors.A,
-    BA09_Upr: DefaultClassColors.B,
-    BA09_Lwr: DefaultClassColors.A,
-    BA08_Upr: DefaultClassColors.BII,
-    BA08_Lwr: DefaultClassColors.A,
-    BA10_Upr: DefaultClassColors.B,
-    BA10_Lwr: DefaultClassColors.A,
-    BA13_Upr: DefaultClassColors.BII,
-    BA13_Lwr: DefaultClassColors.A,
-    BA16_Upr: DefaultClassColors.BII,
-    BA16_Lwr: DefaultClassColors.A,
-    BA17_Upr: DefaultClassColors.BII,
-    BA17_Lwr: DefaultClassColors.A,
-    BB00_Upr: DefaultClassColors.B,
-    BB00_Lwr: DefaultClassColors.B,
-    BB01_Upr: DefaultClassColors.B,
-    BB01_Lwr: DefaultClassColors.B,
-    BB17_Upr: DefaultClassColors.B,
-    BB17_Lwr: DefaultClassColors.B,
-    BB02_Upr: DefaultClassColors.B,
-    BB02_Lwr: DefaultClassColors.B,
-    BB03_Upr: DefaultClassColors.B,
-    BB03_Lwr: DefaultClassColors.B,
-    BB11_Upr: DefaultClassColors.B,
-    BB11_Lwr: DefaultClassColors.B,
-    BB16_Upr: DefaultClassColors.B,
-    BB16_Lwr: DefaultClassColors.B,
-    BB04_Upr: DefaultClassColors.B,
-    BB04_Lwr: DefaultClassColors.BII,
-    BB05_Upr: DefaultClassColors.B,
-    BB05_Lwr: DefaultClassColors.BII,
-    BB07_Upr: DefaultClassColors.BII,
-    BB07_Lwr: DefaultClassColors.BII,
-    BB08_Upr: DefaultClassColors.BII,
-    BB08_Lwr: DefaultClassColors.BII,
-    BB10_Upr: DefaultClassColors.miB,
-    BB10_Lwr: DefaultClassColors.miB,
-    BB12_Upr: DefaultClassColors.miB,
-    BB12_Lwr: DefaultClassColors.miB,
-    BB13_Upr: DefaultClassColors.miB,
-    BB13_Lwr: DefaultClassColors.miB,
-    BB14_Upr: DefaultClassColors.miB,
-    BB14_Lwr: DefaultClassColors.miB,
-    BB15_Upr: DefaultClassColors.miB,
-    BB15_Lwr: DefaultClassColors.miB,
-    BB20_Upr: DefaultClassColors.miB,
-    BB20_Lwr: DefaultClassColors.miB,
-    IC01_Upr: DefaultClassColors.IC,
-    IC01_Lwr: DefaultClassColors.IC,
-    IC02_Upr: DefaultClassColors.IC,
-    IC02_Lwr: DefaultClassColors.IC,
-    IC03_Upr: DefaultClassColors.IC,
-    IC03_Lwr: DefaultClassColors.IC,
-    IC04_Upr: DefaultClassColors.IC,
-    IC04_Lwr: DefaultClassColors.IC,
-    IC05_Upr: DefaultClassColors.IC,
-    IC05_Lwr: DefaultClassColors.IC,
-    IC06_Upr: DefaultClassColors.IC,
-    IC06_Lwr: DefaultClassColors.IC,
-    IC07_Upr: DefaultClassColors.IC,
-    IC07_Lwr: DefaultClassColors.IC,
-    OP01_Upr: DefaultClassColors.OPN,
-    OP01_Lwr: DefaultClassColors.OPN,
-    OP02_Upr: DefaultClassColors.OPN,
-    OP02_Lwr: DefaultClassColors.OPN,
-    OP03_Upr: DefaultClassColors.OPN,
-    OP03_Lwr: DefaultClassColors.OPN,
-    OP04_Upr: DefaultClassColors.OPN,
-    OP04_Lwr: DefaultClassColors.OPN,
-    OP05_Upr: DefaultClassColors.OPN,
-    OP05_Lwr: DefaultClassColors.OPN,
-    OP06_Upr: DefaultClassColors.OPN,
-    OP06_Lwr: DefaultClassColors.OPN,
-    OP07_Upr: DefaultClassColors.OPN,
-    OP07_Lwr: DefaultClassColors.OPN,
-    OP08_Upr: DefaultClassColors.OPN,
-    OP08_Lwr: DefaultClassColors.OPN,
-    OP09_Upr: DefaultClassColors.OPN,
-    OP09_Lwr: DefaultClassColors.OPN,
-    OP10_Upr: DefaultClassColors.OPN,
-    OP10_Lwr: DefaultClassColors.OPN,
-    OP11_Upr: DefaultClassColors.OPN,
-    OP11_Lwr: DefaultClassColors.OPN,
-    OP12_Upr: DefaultClassColors.OPN,
-    OP12_Lwr: DefaultClassColors.OPN,
-    OP13_Upr: DefaultClassColors.OPN,
-    OP13_Lwr: DefaultClassColors.OPN,
-    OP14_Upr: DefaultClassColors.OPN,
-    OP14_Lwr: DefaultClassColors.OPN,
-    OP15_Upr: DefaultClassColors.OPN,
-    OP15_Lwr: DefaultClassColors.OPN,
-    OP16_Upr: DefaultClassColors.OPN,
-    OP16_Lwr: DefaultClassColors.OPN,
-    OP17_Upr: DefaultClassColors.OPN,
-    OP17_Lwr: DefaultClassColors.OPN,
-    OP18_Upr: DefaultClassColors.OPN,
-    OP18_Lwr: DefaultClassColors.OPN,
-    OP19_Upr: DefaultClassColors.OPN,
-    OP19_Lwr: DefaultClassColors.OPN,
-    OP20_Upr: DefaultClassColors.OPN,
-    OP20_Lwr: DefaultClassColors.OPN,
-    OP21_Upr: DefaultClassColors.OPN,
-    OP21_Lwr: DefaultClassColors.OPN,
-    OP22_Upr: DefaultClassColors.OPN,
-    OP22_Lwr: DefaultClassColors.OPN,
-    OP23_Upr: DefaultClassColors.OPN,
-    OP23_Lwr: DefaultClassColors.OPN,
-    OP24_Upr: DefaultClassColors.OPN,
-    OP24_Lwr: DefaultClassColors.OPN,
-    OP25_Upr: DefaultClassColors.OPN,
-    OP25_Lwr: DefaultClassColors.OPN,
-    OP26_Upr: DefaultClassColors.OPN,
-    OP26_Lwr: DefaultClassColors.OPN,
-    OP27_Upr: DefaultClassColors.OPN,
-    OP27_Lwr: DefaultClassColors.OPN,
-    OP28_Upr: DefaultClassColors.OPN,
-    OP28_Lwr: DefaultClassColors.OPN,
-    OP29_Upr: DefaultClassColors.OPN,
-    OP29_Lwr: DefaultClassColors.OPN,
-    OP30_Upr: DefaultClassColors.OPN,
-    OP30_Lwr: DefaultClassColors.OPN,
-    OP31_Upr: DefaultClassColors.OPN,
-    OP31_Lwr: DefaultClassColors.OPN,
-    OPS1_Upr: DefaultClassColors.OPN,
-    OPS1_Lwr: DefaultClassColors.OPN,
-    OP1S_Upr: DefaultClassColors.OPN,
-    OP1S_Lwr: DefaultClassColors.SYN,
-    AAS1_Upr: DefaultClassColors.SYN,
-    AAS1_Lwr: DefaultClassColors.A,
-    AB1S_Upr: DefaultClassColors.A,
-    AB1S_Lwr: DefaultClassColors.SYN,
-    AB2S_Upr: DefaultClassColors.A,
-    AB2S_Lwr: DefaultClassColors.SYN,
-    BB1S_Upr: DefaultClassColors.B,
-    BB1S_Lwr: DefaultClassColors.SYN,
-    BB2S_Upr: DefaultClassColors.B,
-    BB2S_Lwr: DefaultClassColors.SYN,
-    BBS1_Upr: DefaultClassColors.SYN,
-    BBS1_Lwr: DefaultClassColors.B,
-    ZZ01_Upr: DefaultClassColors.Z,
-    ZZ01_Lwr: DefaultClassColors.Z,
-    ZZ02_Upr: DefaultClassColors.Z,
-    ZZ02_Lwr: DefaultClassColors.Z,
-    ZZ1S_Upr: DefaultClassColors.Z,
-    ZZ1S_Lwr: DefaultClassColors.SYN,
-    ZZ2S_Upr: DefaultClassColors.Z,
-    ZZ2S_Lwr: DefaultClassColors.SYN,
-    ZZS1_Upr: DefaultClassColors.SYN,
-    ZZS1_Lwr: DefaultClassColors.Z,
-    ZZS2_Upr: DefaultClassColors.SYN,
-    ZZS2_Lwr: DefaultClassColors.Z,
-});
+const PyramidsColors = ColorMap({ ...NtCColors });
 type PyramidsColors = typeof PyramidsColors;
 
 export const ConfalPyramidsColorThemeParams = {
@@ -272,7 +66,7 @@ export const ConfalPyramidsColorThemeProvider: ColorTheme.Provider<ConfalPyramid
     factory: ConfalPyramidsColorTheme,
     getParams: getConfalPyramidsColorThemeParams,
     defaultValues: PD.getDefaultValues(ConfalPyramidsColorThemeParams),
-    isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.models.some(m => ConfalPyramids.isApplicable(m)),
+    isApplicable: (ctx: ThemeDataContext) => !!ctx.structure && ctx.structure.models.some(m => Dnatco.isApplicable(m)),
     ensureCustomProperties: {
         attach: (ctx: CustomProperty.Context, data: ThemeDataContext) => data.structure ? ConfalPyramidsProvider.attach(ctx, data.structure.models[0], void 0, true) : Promise.resolve(),
         detach: (data) => data.structure && ConfalPyramidsProvider.ref(data.structure.models[0], false)

+ 5 - 162
src/extensions/dnatco/confal-pyramids/property.ts

@@ -5,90 +5,18 @@
  * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
  */
 
-import { ConfalPyramidsTypes as CPT } from './types';
-import { Column, Table } from '../../../mol-data/db';
-import { toTable } from '../../../mol-io/reader/cif/schema';
+import { Dnatco, DnatcoParams, DnatcoSteps } from '../property';
 import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
 import { Model } from '../../../mol-model/structure';
 import { CustomProperty } from '../../../mol-model-props/common/custom-property';
 import { CustomModelProperty } from '../../../mol-model-props/common/custom-model-property';
-import { PropertyWrapper } from '../../../mol-model-props/common/wrapper';
 import { ParamDefinition as PD } from '../../../mol-util/param-definition';
-import { MmcifFormat } from '../../../mol-model-formats/structure/mmcif';
 
-export type ConfalPyramids = PropertyWrapper<CPT.Steps | undefined>;
-
-export namespace ConfalPyramids {
-    export const Schema = {
-        ndb_struct_ntc_step: {
-            id: Column.Schema.int,
-            name: Column.Schema.str,
-            PDB_model_number: Column.Schema.int,
-            label_entity_id_1: Column.Schema.int,
-            label_asym_id_1: Column.Schema.str,
-            label_seq_id_1: Column.Schema.int,
-            label_comp_id_1: Column.Schema.str,
-            label_alt_id_1: Column.Schema.str,
-            label_entity_id_2: Column.Schema.int,
-            label_asym_id_2: Column.Schema.str,
-            label_seq_id_2: Column.Schema.int,
-            label_comp_id_2: Column.Schema.str,
-            label_alt_id_2: Column.Schema.str,
-            auth_asym_id_1: Column.Schema.str,
-            auth_seq_id_1: Column.Schema.int,
-            auth_asym_id_2: Column.Schema.str,
-            auth_seq_id_2: Column.Schema.int,
-            PDB_ins_code_1: Column.Schema.str,
-            PDB_ins_code_2: Column.Schema.str,
-        },
-        ndb_struct_ntc_step_summary: {
-            step_id: Column.Schema.int,
-            assigned_CANA: Column.Schema.str,
-            assigned_NtC: Column.Schema.str,
-            confal_score: Column.Schema.int,
-            euclidean_distance_NtC_ideal: Column.Schema.float,
-            cartesian_rmsd_closest_NtC_representative: Column.Schema.float,
-            closest_CANA: Column.Schema.str,
-            closest_NtC: Column.Schema.str,
-            closest_step_golden: Column.Schema.str
-        }
-    };
-    export type Schema = typeof Schema;
-
-    export async function fromCif(ctx: CustomProperty.Context, model: Model, props: ConfalPyramidsProps): Promise<CustomProperty.Data<ConfalPyramids>> {
-        const info = PropertyWrapper.createInfo();
-        const data = getCifData(model);
-        if (data === undefined) return { value: { info, data: undefined } };
-
-        const fromCif = createPyramidsFromCif(model, data.steps, data.stepsSummary);
-        return { value: { info, data: fromCif } };
-    }
-
-    function getCifData(model: Model) {
-        if (!MmcifFormat.is(model.sourceData)) throw new Error('Data format must be mmCIF');
-        if (!hasNdbStructNtcCategories(model)) return undefined;
-        return {
-            steps: toTable(Schema.ndb_struct_ntc_step, model.sourceData.data.frame.categories.ndb_struct_ntc_step),
-            stepsSummary: toTable(Schema.ndb_struct_ntc_step_summary, model.sourceData.data.frame.categories.ndb_struct_ntc_step_summary)
-        };
-    }
-
-    function hasNdbStructNtcCategories(model: Model): boolean {
-        if (!MmcifFormat.is(model.sourceData)) return false;
-        const names = (model.sourceData).data.frame.categoryNames;
-        return names.includes('ndb_struct_ntc_step') && names.includes('ndb_struct_ntc_step_summary');
-    }
-
-    export function isApplicable(model?: Model): boolean {
-        return !!model && hasNdbStructNtcCategories(model);
-    }
-}
-
-export const ConfalPyramidsParams = {};
+export const ConfalPyramidsParams = { ...DnatcoParams };
 export type ConfalPyramidsParams = typeof ConfalPyramidsParams;
 export type ConfalPyramidsProps = PD.Values<ConfalPyramidsParams>;
 
-export const ConfalPyramidsProvider: CustomModelProperty.Provider<ConfalPyramidsParams, ConfalPyramids> = CustomModelProperty.createProvider({
+export const ConfalPyramidsProvider: CustomModelProperty.Provider<ConfalPyramidsParams, DnatcoSteps> = CustomModelProperty.createProvider({
     label: 'Confal Pyramids',
     descriptor: CustomPropertyDescriptor({
         name: 'confal_pyramids',
@@ -96,94 +24,9 @@ export const ConfalPyramidsProvider: CustomModelProperty.Provider<ConfalPyramids
     type: 'static',
     defaultParams: ConfalPyramidsParams,
     getParams: (data: Model) => ConfalPyramidsParams,
-    isApplicable: (data: Model) => ConfalPyramids.isApplicable(data),
+    isApplicable: (data: Model) => Dnatco.isApplicable(data),
     obtain: async (ctx: CustomProperty.Context, data: Model, props: Partial<ConfalPyramidsProps>) => {
         const p = { ...PD.getDefaultValues(ConfalPyramidsParams), ...props };
-        return ConfalPyramids.fromCif(ctx, data, p);
+        return Dnatco.fromCif(ctx, data, p);
     }
 });
-
-type StepsSummaryTable = Table<typeof ConfalPyramids.Schema.ndb_struct_ntc_step_summary>;
-
-function createPyramidsFromCif(
-    model: Model,
-    cifSteps: Table<typeof ConfalPyramids.Schema.ndb_struct_ntc_step>,
-    stepsSummary: StepsSummaryTable
-): CPT.Steps {
-    const steps = new Array<CPT.Step>();
-    const mapping = new Array<CPT.MappedChains>();
-
-    const {
-        id, PDB_model_number, name,
-        auth_asym_id_1, auth_seq_id_1, label_comp_id_1, label_alt_id_1, PDB_ins_code_1,
-        auth_asym_id_2, auth_seq_id_2, label_comp_id_2, label_alt_id_2, PDB_ins_code_2,
-        _rowCount
-    } = cifSteps;
-
-    if (_rowCount !== stepsSummary._rowCount) throw new Error('Inconsistent mmCIF data');
-
-    for (let i = 0; i < _rowCount; i++) {
-        const {
-            NtC,
-            confal_score,
-            rmsd
-        } = getSummaryData(id.value(i), i, stepsSummary);
-        const modelNum = PDB_model_number.value(i);
-        const chainId = auth_asym_id_1.value(i);
-        const seqId = auth_seq_id_1.value(i);
-        const modelIdx = modelNum - 1;
-
-        if (mapping.length <= modelIdx || !mapping[modelIdx])
-            mapping[modelIdx] = new Map<string, CPT.MappedResidues>();
-
-        const step = {
-            PDB_model_number: modelNum,
-            name: name.value(i),
-            auth_asym_id_1: chainId,
-            auth_seq_id_1: seqId,
-            label_comp_id_1: label_comp_id_1.value(i),
-            label_alt_id_1: label_alt_id_1.value(i),
-            PDB_ins_code_1: PDB_ins_code_1.value(i),
-            auth_asym_id_2: auth_asym_id_2.value(i),
-            auth_seq_id_2: auth_seq_id_2.value(i),
-            label_comp_id_2: label_comp_id_2.value(i),
-            label_alt_id_2: label_alt_id_2.value(i),
-            PDB_ins_code_2: PDB_ins_code_2.value(i),
-            confal_score,
-            NtC,
-            rmsd,
-        };
-
-        steps.push(step);
-
-        const mappedChains = mapping[modelIdx];
-        const residuesOnChain = mappedChains.get(chainId) ?? new Map<number, number[]>();
-        const stepsForResidue = residuesOnChain.get(seqId) ?? [];
-        stepsForResidue.push(steps.length - 1);
-
-        residuesOnChain.set(seqId, stepsForResidue);
-        mappedChains.set(chainId, residuesOnChain);
-        mapping[modelIdx] = mappedChains;
-    }
-
-    return { steps, mapping };
-}
-
-function getSummaryData(id: number, i: number, stepsSummary: StepsSummaryTable) {
-    const {
-        step_id,
-        confal_score,
-        assigned_NtC,
-        cartesian_rmsd_closest_NtC_representative,
-    } = stepsSummary;
-
-    // Assume that step_ids in ntc_step_summary are in the same order as steps in ntc_step
-    for (let j = i; j < stepsSummary._rowCount; j++) {
-        if (id === step_id.value(j)) return { NtC: assigned_NtC.value(j), confal_score: confal_score.value(j), rmsd: cartesian_rmsd_closest_NtC_representative.value(j) };
-    }
-    // Safety net for cases where the previous assumption is not met
-    for (let j = 0; j < i; j++) {
-        if (id === step_id.value(j)) return { NtC: assigned_NtC.value(j), confal_score: confal_score.value(j), rmsd: cartesian_rmsd_closest_NtC_representative.value(j) };
-    }
-    throw new Error('Inconsistent mmCIF data');
-}

+ 3 - 2
src/extensions/dnatco/confal-pyramids/representation.ts

@@ -5,9 +5,10 @@
  * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
  */
 
-import { ConfalPyramids, ConfalPyramidsProvider } from './property';
+import { ConfalPyramidsProvider } from './property';
 import { ConfalPyramidsIterator } from './util';
 import { ConfalPyramidsTypes as CPT } from './types';
+import { Dnatco } from '../property';
 import { Interval } from '../../../mol-data/int';
 import { Mesh } from '../../../mol-geo/geometry/mesh/mesh';
 import { MeshBuilder } from '../../../mol-geo/geometry/mesh/mesh-builder';
@@ -197,7 +198,7 @@ export const ConfalPyramidsRepresentationProvider = StructureRepresentationProvi
     defaultValues: PD.getDefaultValues(ConfalPyramidsParams),
     defaultColorTheme: { name: 'confal-pyramids' },
     defaultSizeTheme: { name: 'uniform' },
-    isApplicable: (structure: Structure) => structure.models.some(m => ConfalPyramids.isApplicable(m)),
+    isApplicable: (structure: Structure) => structure.models.some(m => Dnatco.isApplicable(m)),
     ensureCustomProperties: {
         attach: (ctx: CustomProperty.Context, structure: Structure) => ConfalPyramidsProvider.attach(ctx, structure.model, void 0, true),
         detach: (data) => ConfalPyramidsProvider.ref(data.model, false),

+ 9 - 41
src/extensions/dnatco/confal-pyramids/types.ts

@@ -5,61 +5,29 @@
  * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
  */
 
+import { DnatcoTypes } from '../types';
 import { DataLocation } from '../../../mol-model/location';
 import { DataLoci } from '../../../mol-model/loci';
 import { confalPyramidLabel } from './behavior';
 
 export namespace ConfalPyramidsTypes {
-    export const DataTag = 'dnatco-confal-half-pyramid';
+    export interface Location extends DataLocation<DnatcoTypes.HalfStep, {}> {}
 
-    export type Step = {
-        PDB_model_number: number,
-        name: string,
-        auth_asym_id_1: string,
-        auth_seq_id_1: number,
-        label_comp_id_1: string,
-        label_alt_id_1: string,
-        PDB_ins_code_1: string,
-        auth_asym_id_2: string,
-        auth_seq_id_2: number,
-        label_comp_id_2: string,
-        label_alt_id_2: string,
-        PDB_ins_code_2: string,
-        confal_score: number,
-        NtC: string,
-        rmsd: number,
-    }
-
-    export type MappedChains = Map<string, MappedResidues>;
-    export type MappedResidues = Map<number, number[]>;
-
-    export interface Steps {
-        steps: Array<Step>,
-        mapping: MappedChains[],
-    }
-
-    export interface HalfPyramid {
-        step: Step,
-        isLower: boolean,
-    }
-
-    export interface Location extends DataLocation<HalfPyramid, {}> {}
-
-    export function Location(step: Step, isLower: boolean) {
-        return DataLocation(DataTag, { step, isLower }, {});
+    export function Location(step: DnatcoTypes.Step, isLower: boolean) {
+        return DataLocation(DnatcoTypes.DataTag, { step, isLower }, {});
     }
 
     export function isLocation(x: any): x is Location {
-        return !!x && x.kind === 'data-location' && x.tag === DataTag;
+        return !!x && x.kind === 'data-location' && x.tag === DnatcoTypes.DataTag;
     }
 
-    export interface Loci extends DataLoci<HalfPyramid, {}> {}
+    export interface Loci extends DataLoci<DnatcoTypes.HalfStep, {}> {}
 
-    export function Loci(data: HalfPyramid, elements: ReadonlyArray<{}>): Loci {
-        return DataLoci(DataTag, data, elements, undefined, () => confalPyramidLabel(data));
+    export function Loci(data: DnatcoTypes.HalfStep, elements: ReadonlyArray<{}>): Loci {
+        return DataLoci(DnatcoTypes.DataTag, data, elements, undefined, () => confalPyramidLabel(data));
     }
 
     export function isLoci(x: any): x is Loci {
-        return !!x && x.kind === 'data-loci' && x.tag === DataTag;
+        return !!x && x.kind === 'data-loci' && x.tag === DnatcoTypes.DataTag;
     }
 }

+ 16 - 50
src/extensions/dnatco/confal-pyramids/util.ts

@@ -6,11 +6,10 @@
  */
 
 import { ConfalPyramidsProvider } from './property';
-import { ConfalPyramidsTypes as CPT } from './types';
+import { DnatcoTypes } from '../types';
+import { DnatcoUtil } from '../util';
 import { Segmentation } from '../../../mol-data/int';
-import { ChainIndex, ElementIndex, ResidueIndex, Structure, StructureElement, StructureProperties, Unit } from '../../../mol-model/structure';
-
-type Residue = Segmentation.Segment<ResidueIndex>;
+import { ChainIndex, ElementIndex, ResidueIndex, Structure, StructureElement, Unit } from '../../../mol-model/structure';
 
 export type Pyramid = {
     O3: ElementIndex,
@@ -22,31 +21,12 @@ export type Pyramid = {
     stepIdx: number,
 };
 
-const EmptyStepIndices = new Array<number>();
-
-function copyResidue(r?: Residue) {
-    return r ? { index: r.index, start: r.start, end: r.end } : void 0;
-}
-
-function getAtomIndex(loc: StructureElement.Location, residue: Residue, names: string[], altId: string): ElementIndex {
-    for (let eI = residue.start; eI < residue.end; eI++) {
-        loc.element = loc.unit.elements[eI];
-        const elName = StructureProperties.atom.label_atom_id(loc);
-        const elAltId = StructureProperties.atom.label_alt_id(loc);
-
-        if (names.includes(elName) && (elAltId === altId || elAltId.length === 0))
-            return loc.element;
-    }
-
-    return -1 as ElementIndex;
-}
-
-function getPyramid(loc: StructureElement.Location, one: Residue, two: Residue, altIdOne: string, altIdTwo: string, confalScore: number, stepIdx: number): Pyramid {
-    const O3 = getAtomIndex(loc, one, ['O3\'', 'O3*'], altIdOne);
-    const P = getAtomIndex(loc, two, ['P'], altIdTwo);
-    const OP1 = getAtomIndex(loc, two, ['OP1'], altIdTwo);
-    const OP2 = getAtomIndex(loc, two, ['OP2'], altIdTwo);
-    const O5 = getAtomIndex(loc, two, ['O5\'', 'O5*'], altIdTwo);
+function getPyramid(loc: StructureElement.Location, one: DnatcoUtil.Residue, two: DnatcoUtil.Residue, altIdOne: string, altIdTwo: string, confalScore: number, stepIdx: number): Pyramid {
+    const O3 = DnatcoUtil.getAtomIndex(loc, one, ['O3\'', 'O3*'], altIdOne);
+    const P = DnatcoUtil.getAtomIndex(loc, two, ['P'], altIdTwo);
+    const OP1 = DnatcoUtil.getAtomIndex(loc, two, ['OP1'], altIdTwo);
+    const OP2 = DnatcoUtil.getAtomIndex(loc, two, ['OP2'], altIdTwo);
+    const O5 = DnatcoUtil.getAtomIndex(loc, two, ['O5\'', 'O5*'], altIdTwo);
 
     return { O3, P, OP1, OP2, O5, confalScore, stepIdx };
 }
@@ -54,34 +34,20 @@ function getPyramid(loc: StructureElement.Location, one: Residue, two: Residue,
 export class ConfalPyramidsIterator {
     private chainIt: Segmentation.SegmentIterator<ChainIndex>;
     private residueIt: Segmentation.SegmentIterator<ResidueIndex>;
-    private residueOne?: Residue;
-    private residueTwo: Residue;
-    private data?: CPT.Steps;
+    private residueOne?: DnatcoUtil.Residue;
+    private residueTwo: DnatcoUtil.Residue;
+    private data?: DnatcoTypes.Steps;
     private loc: StructureElement.Location;
 
-    private getStepIndices(r: Residue) {
-        this.loc.element = this.loc.unit.elements[r.start];
-
-        const modelIdx = StructureProperties.unit.model_num(this.loc) - 1;
-        const chainId = StructureProperties.chain.auth_asym_id(this.loc);
-        const seqId = StructureProperties.residue.auth_seq_id(this.loc);
-
-        const chains = this.data!.mapping[modelIdx];
-        if (!chains) return EmptyStepIndices;
-        const residues = chains.get(chainId);
-        if (!residues) return EmptyStepIndices;
-        return residues.get(seqId) ?? EmptyStepIndices;
-    }
-
     private moveStep() {
-        this.residueOne = copyResidue(this.residueTwo);
-        this.residueTwo = copyResidue(this.residueIt.move())!;
+        this.residueOne = DnatcoUtil.copyResidue(this.residueTwo);
+        this.residueTwo = DnatcoUtil.copyResidue(this.residueIt.move())!;
 
         return this.toPyramids(this.residueOne!, this.residueTwo);
     }
 
-    private toPyramids(one: Residue, two: Residue) {
-        const indices = this.getStepIndices(one);
+    private toPyramids(one: DnatcoUtil.Residue, two: DnatcoUtil.Residue) {
+        const indices = DnatcoUtil.getStepIndices(this.data!, this.loc, one);
 
         const points = [];
         for (const idx of indices) {

+ 172 - 0
src/extensions/dnatco/property.ts

@@ -0,0 +1,172 @@
+/**
+ * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Michal Malý <michal.maly@ibt.cas.cz>
+ * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
+ */
+
+import { DnatcoTypes } from './types';
+import { Column, Table } from '../../mol-data/db';
+import { toTable } from '../../mol-io/reader/cif/schema';
+import { Model } from '../../mol-model/structure';
+import { CustomProperty } from '../../mol-model-props/common/custom-property';
+import { PropertyWrapper } from '../../mol-model-props/common/wrapper';
+import { MmcifFormat } from '../../mol-model-formats/structure/mmcif';
+import { ParamDefinition as PD } from '../../mol-util/param-definition';
+
+export type DnatcoSteps = PropertyWrapper<DnatcoTypes.Steps | undefined>;
+
+export const DnatcoParams = {};
+export type DnatcoParams = typeof DnatcoParams;
+export type DnatcoProps = PD.Values<DnatcoParams>;
+
+export namespace Dnatco {
+    export const Schema = {
+        ndb_struct_ntc_step: {
+            id: Column.Schema.int,
+            name: Column.Schema.str,
+            PDB_model_number: Column.Schema.int,
+            label_entity_id_1: Column.Schema.int,
+            label_asym_id_1: Column.Schema.str,
+            label_seq_id_1: Column.Schema.int,
+            label_comp_id_1: Column.Schema.str,
+            label_alt_id_1: Column.Schema.str,
+            label_entity_id_2: Column.Schema.int,
+            label_asym_id_2: Column.Schema.str,
+            label_seq_id_2: Column.Schema.int,
+            label_comp_id_2: Column.Schema.str,
+            label_alt_id_2: Column.Schema.str,
+            auth_asym_id_1: Column.Schema.str,
+            auth_seq_id_1: Column.Schema.int,
+            auth_asym_id_2: Column.Schema.str,
+            auth_seq_id_2: Column.Schema.int,
+            PDB_ins_code_1: Column.Schema.str,
+            PDB_ins_code_2: Column.Schema.str,
+        },
+        ndb_struct_ntc_step_summary: {
+            step_id: Column.Schema.int,
+            assigned_CANA: Column.Schema.str,
+            assigned_NtC: Column.Schema.str,
+            confal_score: Column.Schema.int,
+            euclidean_distance_NtC_ideal: Column.Schema.float,
+            cartesian_rmsd_closest_NtC_representative: Column.Schema.float,
+            closest_CANA: Column.Schema.str,
+            closest_NtC: Column.Schema.str,
+            closest_step_golden: Column.Schema.str
+        }
+    };
+    export type Schema = typeof Schema;
+
+    export async function fromCif(ctx: CustomProperty.Context, model: Model, props: DnatcoProps): Promise<CustomProperty.Data<DnatcoSteps>> {
+        const info = PropertyWrapper.createInfo();
+        const data = getCifData(model);
+        if (data === undefined) return { value: { info, data: undefined } };
+
+        const fromCif = createPyramidsFromCif(model, data.steps, data.stepsSummary);
+        return { value: { info, data: fromCif } };
+    }
+
+    function getCifData(model: Model) {
+        if (!MmcifFormat.is(model.sourceData)) throw new Error('Data format must be mmCIF');
+        if (!hasNdbStructNtcCategories(model)) return undefined;
+        return {
+            steps: toTable(Schema.ndb_struct_ntc_step, model.sourceData.data.frame.categories.ndb_struct_ntc_step),
+            stepsSummary: toTable(Schema.ndb_struct_ntc_step_summary, model.sourceData.data.frame.categories.ndb_struct_ntc_step_summary)
+        };
+    }
+
+    function hasNdbStructNtcCategories(model: Model): boolean {
+        if (!MmcifFormat.is(model.sourceData)) return false;
+        const names = (model.sourceData).data.frame.categoryNames;
+        return names.includes('ndb_struct_ntc_step') && names.includes('ndb_struct_ntc_step_summary');
+    }
+
+    export function isApplicable(model?: Model): boolean {
+        return !!model && hasNdbStructNtcCategories(model);
+    }
+}
+
+type StepsSummaryTable = Table<typeof Dnatco.Schema.ndb_struct_ntc_step_summary>;
+
+function createPyramidsFromCif(
+    model: Model,
+    cifSteps: Table<typeof Dnatco.Schema.ndb_struct_ntc_step>,
+    stepsSummary: StepsSummaryTable
+): DnatcoTypes.Steps {
+    const steps = new Array<DnatcoTypes.Step>();
+    const mapping = new Array<DnatcoTypes.MappedChains>();
+
+    const {
+        id, PDB_model_number, name,
+        auth_asym_id_1, auth_seq_id_1, label_comp_id_1, label_alt_id_1, PDB_ins_code_1,
+        auth_asym_id_2, auth_seq_id_2, label_comp_id_2, label_alt_id_2, PDB_ins_code_2,
+        _rowCount
+    } = cifSteps;
+
+    if (_rowCount !== stepsSummary._rowCount) throw new Error('Inconsistent mmCIF data');
+
+    for (let i = 0; i < _rowCount; i++) {
+        const {
+            NtC,
+            confal_score,
+            rmsd
+        } = getSummaryData(id.value(i), i, stepsSummary);
+        const modelNum = PDB_model_number.value(i);
+        const chainId = auth_asym_id_1.value(i);
+        const seqId = auth_seq_id_1.value(i);
+        const modelIdx = modelNum - 1;
+
+        if (mapping.length <= modelIdx || !mapping[modelIdx])
+            mapping[modelIdx] = new Map<string, DnatcoTypes.MappedResidues>();
+
+        const step = {
+            PDB_model_number: modelNum,
+            name: name.value(i),
+            auth_asym_id_1: chainId,
+            auth_seq_id_1: seqId,
+            label_comp_id_1: label_comp_id_1.value(i),
+            label_alt_id_1: label_alt_id_1.value(i),
+            PDB_ins_code_1: PDB_ins_code_1.value(i),
+            auth_asym_id_2: auth_asym_id_2.value(i),
+            auth_seq_id_2: auth_seq_id_2.value(i),
+            label_comp_id_2: label_comp_id_2.value(i),
+            label_alt_id_2: label_alt_id_2.value(i),
+            PDB_ins_code_2: PDB_ins_code_2.value(i),
+            confal_score,
+            NtC,
+            rmsd,
+        };
+
+        steps.push(step);
+
+        const mappedChains = mapping[modelIdx];
+        const residuesOnChain = mappedChains.get(chainId) ?? new Map<number, number[]>();
+        const stepsForResidue = residuesOnChain.get(seqId) ?? [];
+        stepsForResidue.push(steps.length - 1);
+
+        residuesOnChain.set(seqId, stepsForResidue);
+        mappedChains.set(chainId, residuesOnChain);
+        mapping[modelIdx] = mappedChains;
+    }
+
+    return { steps, mapping };
+}
+
+function getSummaryData(id: number, i: number, stepsSummary: StepsSummaryTable) {
+    const {
+        step_id,
+        confal_score,
+        assigned_NtC,
+        cartesian_rmsd_closest_NtC_representative,
+    } = stepsSummary;
+
+    // Assume that step_ids in ntc_step_summary are in the same order as steps in ntc_step
+    for (let j = i; j < stepsSummary._rowCount; j++) {
+        if (id === step_id.value(j)) return { NtC: assigned_NtC.value(j), confal_score: confal_score.value(j), rmsd: cartesian_rmsd_closest_NtC_representative.value(j) };
+    }
+    // Safety net for cases where the previous assumption is not met
+    for (let j = 0; j < i; j++) {
+        if (id === step_id.value(j)) return { NtC: assigned_NtC.value(j), confal_score: confal_score.value(j), rmsd: cartesian_rmsd_closest_NtC_representative.value(j) };
+    }
+    throw new Error('Inconsistent mmCIF data');
+}

+ 41 - 0
src/extensions/dnatco/types.ts

@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author Michal Malý <michal.maly@ibt.cas.cz>
+ * @author Jiří Černý <jiri.cerny@ibt.cas.cz>
+ */
+
+export namespace DnatcoTypes {
+    export const DataTag = 'dnatco-confal-half-step';
+
+    export type Step = {
+        PDB_model_number: number,
+        name: string,
+        auth_asym_id_1: string,
+        auth_seq_id_1: number,
+        label_comp_id_1: string,
+        label_alt_id_1: string,
+        PDB_ins_code_1: string,
+        auth_asym_id_2: string,
+        auth_seq_id_2: number,
+        label_comp_id_2: string,
+        label_alt_id_2: string,
+        PDB_ins_code_2: string,
+        confal_score: number,
+        NtC: string,
+        rmsd: number,
+    }
+
+    export type MappedChains = Map<string, MappedResidues>;
+    export type MappedResidues = Map<number, number[]>;
+
+    export interface Steps {
+        steps: Array<Step>,
+        mapping: MappedChains[],
+    }
+
+    export interface HalfStep {
+        step: Step,
+        isLower: boolean,
+    }
+}

+ 40 - 0
src/extensions/dnatco/util.ts

@@ -0,0 +1,40 @@
+import { DnatcoTypes } from './types';
+import { Segmentation } from '../../mol-data/int';
+import { ElementIndex, ResidueIndex, StructureElement, StructureProperties } from '../../mol-model/structure';
+
+const EmptyStepIndices = new Array<number>();
+
+export namespace DnatcoUtil {
+    export type Residue = Segmentation.Segment<ResidueIndex>;
+
+    export function copyResidue(r?: Residue) {
+        return r ? { index: r.index, start: r.start, end: r.end } : void 0;
+    }
+
+    export function getAtomIndex(loc: StructureElement.Location, residue: Residue, names: string[], altId: string): ElementIndex {
+        for (let eI = residue.start; eI < residue.end; eI++) {
+            loc.element = loc.unit.elements[eI];
+            const elName = StructureProperties.atom.label_atom_id(loc);
+            const elAltId = StructureProperties.atom.label_alt_id(loc);
+
+            if (names.includes(elName) && (elAltId === altId || elAltId.length === 0))
+                return loc.element;
+        }
+
+        return -1 as ElementIndex;
+    }
+
+    export function getStepIndices(data: DnatcoTypes.Steps, loc: StructureElement.Location, r: DnatcoUtil.Residue) {
+        loc.element = loc.unit.elements[r.start];
+
+        const modelIdx = StructureProperties.unit.model_num(loc) - 1;
+        const chainId = StructureProperties.chain.auth_asym_id(loc);
+        const seqId = StructureProperties.residue.auth_seq_id(loc);
+
+        const chains = data.mapping[modelIdx];
+        if (!chains) return EmptyStepIndices;
+        const residues = chains.get(chainId);
+        if (!residues) return EmptyStepIndices;
+        return residues.get(seqId) ?? EmptyStepIndices;
+    }
+}