Skip to content
Snippets Groups Projects
Select Git revision
  • 40aa847d1f9c5d2a1a5161ecedb879c2657f9416
  • master default protected
  • rednatco-v2
  • rednatco
  • test
  • ntc-tube-uniform-color
  • ntc-tube-missing-atoms
  • restore-vertex-array-per-program
  • watlas2
  • dnatco_new
  • cleanup-old-nodejs
  • webmmb
  • fix_auth_seq_id
  • update_deps
  • ext_dev
  • ntc_balls
  • nci-2
  • plugin
  • bugfix-0.4.5
  • nci
  • servers
  • v0.5.0-dev.1
  • v0.4.5
  • v0.4.4
  • v0.4.3
  • v0.4.2
  • v0.4.1
  • v0.4.0
  • v0.3.12
  • v0.3.11
  • v0.3.10
  • v0.3.9
  • v0.3.8
  • v0.3.7
  • v0.3.6
  • v0.3.5
  • v0.3.4
  • v0.3.3
  • v0.3.2
  • v0.3.1
  • v0.3.0
41 results

graph.ts

Blame
  • assembly.ts 5.15 KiB
    /**
     * Copyright (c) 2017 mol* contributors, licensed under MIT, See LICENSE file for more info.
     *
     * @author David Sehnal <david.sehnal@gmail.com>
     */
    
    import { Mat4, Tensor } from 'mol-math/linear-algebra'
    import SymmetryOperator from 'mol-math/geometry/symmetry-operator'
    import Format from '../../format'
    import { Assembly, OperatorGroup, OperatorGroups } from '../../properties/symmetry'
    import { Queries as Q, Query } from '../../../query'
    
    import mmCIF_Format = Format.mmCIF
    
    export default function create(format: mmCIF_Format): ReadonlyArray<Assembly> {
        const { pdbx_struct_assembly } = format.data;
        if (!pdbx_struct_assembly._rowCount) return [];
    
        const matrices = getMatrices(format);
        const assemblies: Assembly[] = [];
        for (let i = 0; i < pdbx_struct_assembly._rowCount; i++) {
            assemblies[assemblies.length] = createAssembly(format, i, matrices);
        }
        return assemblies;
    }
    
    type Matrices = Map<string, Mat4>
    type Generator = { expression: string, asymIds: string[] }
    
    function createAssembly(format: mmCIF_Format, index: number, matrices: Matrices): Assembly {
        const { pdbx_struct_assembly, pdbx_struct_assembly_gen } = format.data;
    
        const id = pdbx_struct_assembly.id.value(index);
        const details = pdbx_struct_assembly.details.value(index);
        const generators: Generator[] = [];
    
        const { assembly_id, oper_expression, asym_id_list } = pdbx_struct_assembly_gen;
    
        for (let i = 0, _i = pdbx_struct_assembly_gen._rowCount; i < _i; i++) {
            if (assembly_id.value(i) !== id) continue;
            generators[generators.length] = {
                expression: oper_expression.value(i),
                asymIds: asym_id_list.value(i)
            };
        }
    
        return Assembly.create(id, details, operatorGroupsProvider(generators, matrices));
    }
    
    function operatorGroupsProvider(generators: Generator[], matrices: Matrices): () => OperatorGroups {
        return () => {
            const groups: OperatorGroup[] = [];
    
            let operatorOffset = 0;
            for (let i = 0; i < generators.length; i++) {
                const gen = generators[i];
                const operatorList = parseOperatorList(gen.expression);
                const operatorNames = expandOperators(operatorList);
                const operators = getAssemblyOperators(matrices, operatorNames, operatorOffset);
                const selector = Query(Q.generators.atoms({ chainTest: Q.pred.and(
                    Q.pred.eq(Q.props.unit.operator_name, SymmetryOperator.DefaultName),
                    Q.pred.inSet(Q.props.chain.label_asym_id, gen.asymIds)
                )}));
                groups[groups.length] = { selector, operators };
                operatorOffset += operators.length;
            }
    
            return groups;
        }
    }
    
    function getMatrices({ data }: mmCIF_Format): Matrices {
        const { pdbx_struct_oper_list } = data;
        const { id, matrix, vector, _schema } = pdbx_struct_oper_list;
        const matrices = new Map<string, Mat4>();
    
        for (let i = 0, _i = pdbx_struct_oper_list._rowCount; i < _i; i++) {
            const m = Tensor.toMat4(_schema.matrix.space, matrix.value(i));
            const t = Tensor.toVec3(_schema.vector.space, vector.value(i));
            Mat4.setTranslation(m, t);
            Mat4.setValue(m, 3, 3, 1);
            matrices.set(id.value(i), m);
        }
    
        return matrices;
    }
    
    function expandOperators(operatorList: string[][]) {
        const ops: string[][] = [];
        const currentOp: string[] = [];
        for (let i = 0; i < operatorList.length; i++) currentOp[i] = '';
        expandOperators1(operatorList, ops, operatorList.length - 1, currentOp);
        return ops;
    }
    
    function expandOperators1(operatorNames: string[][], list: string[][], i: number, current: string[]) {
        if (i < 0) {
            list[list.length] = current.slice(0);
            return;
        }
    
        let ops = operatorNames[i], len = ops.length;
        for (let j = 0; j < len; j++) {
            current[i] = ops[j];
            expandOperators1(operatorNames, list, i - 1, current);
        }
    }
    
    function getAssemblyOperators(matrices: Matrices, operatorNames: string[][], startIndex: number) {
        const operators: SymmetryOperator[] = [];
    
        let index = startIndex;
        for (let op of operatorNames) {
            let m = Mat4.identity();
            for (let i = 0; i < op.length; i++) {
                Mat4.mul(m, m, matrices.get(op[i])!);
            }
            index++;
            operators[operators.length] = SymmetryOperator.create(`A-${index}`, m);
        }
    
        return operators;
    }
    
    function parseOperatorList(value: string): string[][] {
        // '(X0)(1-5)' becomes [['X0'], ['1', '2', '3', '4', '5']]
        // kudos to Glen van Ginkel.
    
        const oeRegex = /\(?([^\(\)]+)\)?]*/g, groups: string[] = [], ret: string[][] = [];
    
        let g: any;
        while (g = oeRegex.exec(value)) groups[groups.length] = g[1];
    
        groups.forEach(g => {
            const group: string[] = [];
            g.split(',').forEach(e => {
                const dashIndex = e.indexOf('-');
                if (dashIndex > 0) {
                    const from = parseInt(e.substring(0, dashIndex)), to = parseInt(e.substr(dashIndex + 1));
                    for (let i = from; i <= to; i++) group[group.length] = i.toString();
                } else {
                    group[group.length] = e.trim();
                }
            });
            ret[ret.length] = group;
        });
    
        return ret;
    }