Skip to content
Snippets Groups Projects
Select Git revision
  • 871f9635e390348aa843c3130d30a316c65ac249
  • master default protected
  • rednatco-v2
  • base-pairs-ladder
  • 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
  • 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

pass.ts

Blame
  • pass.ts 7.31 KiB
    /**
     * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
     *
     * @author David Sehnal <david.sehnal@gmail.com>
     */
    
    import { QuadSchema, QuadValues } from '../../../mol-gl/compute/util';
    import { ComputeRenderable, createComputeRenderable } from '../../../mol-gl/renderable';
    import { TextureSpec, UniformSpec, Values } from '../../../mol-gl/renderable/schema';
    import { ShaderCode } from '../../../mol-gl/shader-code';
    import quad_vert from '../../../mol-gl/shader/quad.vert';
    import { WebGLContext } from '../../../mol-gl/webgl/context';
    import { createComputeRenderItem } from '../../../mol-gl/webgl/render-item';
    import { RenderTarget } from '../../../mol-gl/webgl/render-target';
    import { ValueCell } from '../../../mol-util';
    import { arrayMin } from '../../../mol-util/array';
    import { CollocationParams } from '../collocation';
    import { normalizeBasicOrder } from '../orbitals';
    import shader_frag from './shader.frag';
    
    const AlphaOrbitalsSchema = {
        ...QuadSchema,
        uDimensions: UniformSpec('v3'),
        uMin: UniformSpec('v3'),
        uDelta: UniformSpec('v3'),
        tCenters: TextureSpec('image-float32', 'rgba', 'float', 'nearest'),
        tInfo: TextureSpec('image-float32', 'rgba', 'float', 'nearest'),
        tCoeff: TextureSpec('image-float32', 'rgb', 'float', 'nearest'),
        tAlpha: TextureSpec('image-float32', 'alpha', 'float', 'nearest'),
        uNCenters: UniformSpec('i'),
        uNAlpha: UniformSpec('i'),
        uNCoeff: UniformSpec('i'),
        uLittleEndian: UniformSpec('i') // TODO: boolean uniforms
    };
    const AlphaOrbitalsShaderCode = ShaderCode('postprocessing', quad_vert, shader_frag);
    type AlphaOrbitalsRenderable = ComputeRenderable<Values<typeof AlphaOrbitalsSchema>>
    
    function createTextureData({
        basis,
        sphericalOrder,
        alphaOrbitals,
        cutoffThreshold
    }: CollocationParams) {
        let centerCount = 0;
        let baseCount = 0;
        let coeffCount = 0;
        for (const atom of basis.atoms) {
            for (const shell of atom.shells) {
                for (const L of shell.angularMomentum) {
                    if (L > 4) {
                        // TODO: will L > 4 be required? Would need to precompute more functions in that case.
                        throw new Error('Angular momentum L > 4 not supported.');
                    }
    
                    centerCount++;
                    baseCount += 2 * L + 1;
                    coeffCount += shell.exponents.length;
                }
            }
        }
    
        const centers = new Float32Array(4 * centerCount);
        // L, alpha_offset, coeff_offset_start, coeff_offset_end
        const info = new Float32Array(4 * centerCount);
        const alpha = new Float32Array(baseCount);
        const coeff = new Float32Array(3 * coeffCount);
    
        let cO = 0, aO = 0, coeffO = 0;
        for (const atom of basis.atoms) {
            for (const shell of atom.shells) {
    
                let amIndex = 0;
                for (const L of shell.angularMomentum) {
                    const a0 = normalizeBasicOrder(L, alphaOrbitals.slice(aO, aO + 2 * L + 1), sphericalOrder);
    
                    const cutoffRadius = cutoffThreshold > 0
                        ? Math.sqrt(-Math.log(cutoffThreshold) / arrayMin(shell.exponents))
                        : 10000;
    
                    centers[4 * cO + 0] = atom.center[0];
                    centers[4 * cO + 1] = atom.center[1];
                    centers[4 * cO + 2] = atom.center[2];
                    centers[4 * cO + 3] = cutoffRadius * cutoffRadius;
    
                    info[4 * cO + 0] = L;
                    info[4 * cO + 1] = aO;
                    info[4 * cO + 2] = coeffO;
                    info[4 * cO + 3] = coeffO + shell.exponents.length;
    
                    for (let i = 0; i < a0.length; i++) alpha[aO + i] = a0[i];
    
                    const c0 = shell.coefficients[amIndex++];
                    for (let i = 0; i < shell.exponents.length; i++) {
                        coeff[3 * (coeffO + i) + 0] = c0[i];
                        coeff[3 * (coeffO + i) + 1] = shell.exponents[i];
                    }
    
                    cO++;
                    aO += 2 * L + 1;
                    coeffO += shell.exponents.length;
                }
            }
        }
    
        return { nCenters: centerCount, nAlpha: baseCount, nCoeff: coeffCount, centers, info, alpha, coeff };
    }
    
    function getPostprocessingRenderable(ctx: WebGLContext, params: CollocationParams): AlphaOrbitalsRenderable {
        const data = createTextureData(params);
    
        // console.log(data);
    
        const values: Values<typeof AlphaOrbitalsSchema> = {
            ...QuadValues,
            uDimensions: ValueCell.create(params.grid.dimensions),
            uMin: ValueCell.create(params.grid.box.min),
            uDelta: ValueCell.create(params.grid.delta),
            uNCenters: ValueCell.create(data.nCenters),
            uNAlpha: ValueCell.create(data.nAlpha),
            uNCoeff: ValueCell.create(data.nCoeff),
            tCenters: ValueCell.create({ width: data.nCenters, height: 1, array: data.centers }),
            tInfo: ValueCell.create({ width: data.nCenters, height: 1, array: data.info }),
            tCoeff: ValueCell.create({ width: data.nCoeff, height: 1, array: data.coeff }),
            tAlpha: ValueCell.create({ width: data.nAlpha, height: 1, array: data.alpha }),
            uLittleEndian: ValueCell.create(isLittleEndian()),
        };
    
        const schema = { ...AlphaOrbitalsSchema };
        const renderItem = createComputeRenderItem(ctx, 'triangles', AlphaOrbitalsShaderCode, schema, values);
    
        return createComputeRenderable(renderItem, values);
    }
    
    export class AlphaOrbitalsPass {
        target: RenderTarget
        renderable: AlphaOrbitalsRenderable
    
        constructor(private webgl: WebGLContext, private params: CollocationParams) {
            const [nx, ny, nz] = params.grid.dimensions;
    
            // TODO: add single component float32 render target option for WebGL2?
            // TODO: figure out the ordering so that it does not have to be remapped in the shader
            this.target = webgl.createRenderTarget(nx, ny * nz, false, 'uint8', 'nearest');
            this.renderable = getPostprocessingRenderable(webgl, params);
        }
    
        private render() {
            const [nx, ny, nz] = this.params.grid.dimensions;
            const width = nx;
            const height = ny * nz;
            const { gl, state } = this.webgl;
            this.target.bind();
            gl.viewport(0, 0, width, height);
            gl.scissor(0, 0, width, height);
            state.disable(gl.SCISSOR_TEST);
            state.disable(gl.BLEND);
            state.disable(gl.DEPTH_TEST);
            state.depthMask(false);
            this.renderable.render();
        }
    
        getData() {
            const [nx, ny, nz] = this.params.grid.dimensions;
            const width = nx;
            const height = ny * nz;
    
            this.render();
            this.target.bind();
            const array = new Uint8Array(width * height * 4);
            this.webgl.readPixels(0, 0, width, height, array);
            // PixelData.flipY({ array, width, height });
            const floats = new Float32Array(array.buffer, array.byteOffset, width * height);
    
            // console.log(array);
            // console.log(floats);
    
            this.renderable.dispose();
            this.target.destroy();
    
            return floats;
    
            // return new ImageData(new Uint8ClampedArray(array), width, height);
        }
    }
    
    function isLittleEndian() {
        const arrayBuffer = new ArrayBuffer(2);
        const uint8Array = new Uint8Array(arrayBuffer);
        const uint16array = new Uint16Array(arrayBuffer);
        uint8Array[0] = 0xAA; // set first byte
        uint8Array[1] = 0xBB; // set second byte
        if(uint16array[0] === 0xBBAA) return 1;
        return 0;
    }