|
@@ -1,10 +1,10 @@
|
|
/**
|
|
/**
|
|
- * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
|
|
|
+ * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
*
|
|
*
|
|
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
|
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
|
*/
|
|
*/
|
|
|
|
|
|
-import { Box3D } from '../../geometry';
|
|
|
|
|
|
+import { Box3D, fillGridDim } from '../../geometry';
|
|
import { Vec3, Mat4, Tensor } from '../../linear-algebra';
|
|
import { Vec3, Mat4, Tensor } from '../../linear-algebra';
|
|
import { RuntimeContext } from 'mol-task';
|
|
import { RuntimeContext } from 'mol-task';
|
|
import { PositionData, DensityData } from '../common';
|
|
import { PositionData, DensityData } from '../common';
|
|
@@ -13,6 +13,7 @@ import { GaussianDensityProps, getDelta } from '../gaussian-density';
|
|
|
|
|
|
export async function GaussianDensityCPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<DensityData> {
|
|
export async function GaussianDensityCPU(ctx: RuntimeContext, position: PositionData, box: Box3D, radius: (index: number) => number, props: GaussianDensityProps): Promise<DensityData> {
|
|
const { resolution, radiusOffset, smoothness } = props
|
|
const { resolution, radiusOffset, smoothness } = props
|
|
|
|
+ const scaleFactor = 1 / resolution
|
|
|
|
|
|
const { indices, x, y, z } = position
|
|
const { indices, x, y, z } = position
|
|
const n = OrderedSet.size(indices)
|
|
const n = OrderedSet.size(indices)
|
|
@@ -31,11 +32,11 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position
|
|
|
|
|
|
const pad = maxRadius * 2 + resolution
|
|
const pad = maxRadius * 2 + resolution
|
|
const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad))
|
|
const expandedBox = Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad))
|
|
- const extent = Vec3.sub(Vec3.zero(), expandedBox.max, expandedBox.min)
|
|
|
|
|
|
+ const extent = Vec3.sub(Vec3(), expandedBox.max, expandedBox.min)
|
|
const min = expandedBox.min
|
|
const min = expandedBox.min
|
|
|
|
|
|
const delta = getDelta(Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad)), resolution)
|
|
const delta = getDelta(Box3D.expand(Box3D.empty(), box, Vec3.create(pad, pad, pad)), resolution)
|
|
- const dim = Vec3.zero()
|
|
|
|
|
|
+ const dim = Vec3()
|
|
Vec3.ceil(dim, Vec3.mul(dim, extent, delta))
|
|
Vec3.ceil(dim, Vec3.mul(dim, extent, delta))
|
|
// console.log('grid dim cpu', dim)
|
|
// console.log('grid dim cpu', dim)
|
|
|
|
|
|
@@ -46,60 +47,59 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position
|
|
const idData = space.create()
|
|
const idData = space.create()
|
|
const idField = Tensor.create(space, idData)
|
|
const idField = Tensor.create(space, idData)
|
|
|
|
|
|
- const iu = dim[2], iv = dim[1], iuv = iu * iv
|
|
|
|
|
|
+ const [ dimX, dimY, dimZ ] = dim
|
|
|
|
+ const iu = dimZ, iv = dimY, iuv = iu * iv
|
|
|
|
|
|
- const densData = space.create()
|
|
|
|
|
|
+ const gridx = fillGridDim(dim[0], min[0], resolution)
|
|
|
|
+ const gridy = fillGridDim(dim[1], min[1], resolution)
|
|
|
|
+ const gridz = fillGridDim(dim[2], min[2], resolution)
|
|
|
|
|
|
- const v = Vec3()
|
|
|
|
- const c = Vec3()
|
|
|
|
|
|
+ const densData = space.create()
|
|
|
|
|
|
const alpha = smoothness
|
|
const alpha = smoothness
|
|
|
|
+ const updateChunk = Math.ceil(1000000 / (Math.pow(maxRadius * 2, 3) * resolution))
|
|
|
|
|
|
- const _r2 = maxRadius * 2
|
|
|
|
- const _radius2 = Vec3.create(_r2, _r2, _r2)
|
|
|
|
- Vec3.mul(_radius2, _radius2, delta)
|
|
|
|
- const updateChunk = Math.ceil(1000000 / (_radius2[0] * _radius2[1] * _radius2[2]))
|
|
|
|
-
|
|
|
|
- const beg = Vec3()
|
|
|
|
- const end = Vec3()
|
|
|
|
- const rad2 = Vec3()
|
|
|
|
-
|
|
|
|
- const gridPad = 1 / Math.max(...delta)
|
|
|
|
-
|
|
|
|
- const invDelta = Vec3.inverse(Vec3(), delta)
|
|
|
|
- const [ invDeltaX, invDeltaY, invDeltaZ ] = invDelta
|
|
|
|
-
|
|
|
|
- console.time('gaussian density cpu')
|
|
|
|
|
|
+ // console.time('gaussian density cpu')
|
|
for (let i = 0; i < n; ++i) {
|
|
for (let i = 0; i < n; ++i) {
|
|
const j = OrderedSet.getAt(indices, i)
|
|
const j = OrderedSet.getAt(indices, i)
|
|
-
|
|
|
|
- Vec3.set(v, x[j], y[j], z[j])
|
|
|
|
- Vec3.sub(v, v, min)
|
|
|
|
- const [ vx, vy, vz ] = v
|
|
|
|
-
|
|
|
|
- Vec3.mul(c, v, delta)
|
|
|
|
|
|
+ const vx = x[j], vy = y[j], vz = z[j]
|
|
|
|
|
|
const rad = radii[i]
|
|
const rad = radii[i]
|
|
const rSq = rad * rad
|
|
const rSq = rad * rad
|
|
const rSqInv = 1 / rSq
|
|
const rSqInv = 1 / rSq
|
|
|
|
|
|
- const r2 = radiusOffset + rad * 2 + gridPad
|
|
|
|
|
|
+ const r2 = rad * 2
|
|
const r2sq = r2 * r2
|
|
const r2sq = r2 * r2
|
|
- Vec3.set(rad2, r2, r2, r2)
|
|
|
|
- Vec3.mul(rad2, rad2, delta)
|
|
|
|
|
|
|
|
- const [ begX, begY, begZ ] = Vec3.floor(beg, Vec3.sub(beg, c, rad2))
|
|
|
|
- const [ endX, endY, endZ ] = Vec3.ceil(end, Vec3.add(end, c, rad2))
|
|
|
|
|
|
+ // Number of grid points, round this up...
|
|
|
|
+ const ng = Math.ceil(r2 * scaleFactor)
|
|
|
|
+
|
|
|
|
+ // Center of the atom, mapped to grid points (take floor)
|
|
|
|
+ const iax = Math.floor(scaleFactor * (vx - min[0]))
|
|
|
|
+ const iay = Math.floor(scaleFactor * (vy - min[1]))
|
|
|
|
+ const iaz = Math.floor(scaleFactor * (vz - min[2]))
|
|
|
|
+
|
|
|
|
+ // Extents of grid to consider for this atom
|
|
|
|
+ const begX = Math.max(0, iax - ng)
|
|
|
|
+ const begY = Math.max(0, iay - ng)
|
|
|
|
+ const begZ = Math.max(0, iaz - ng)
|
|
|
|
+
|
|
|
|
+ // Add two to these points:
|
|
|
|
+ // - iax are floor'd values so this ensures coverage
|
|
|
|
+ // - these are loop limits (exclusive)
|
|
|
|
+ const endX = Math.min(dimX, iax + ng + 2)
|
|
|
|
+ const endY = Math.min(dimY, iay + ng + 2)
|
|
|
|
+ const endZ = Math.min(dimZ, iaz + ng + 2)
|
|
|
|
|
|
for (let xi = begX; xi < endX; ++xi) {
|
|
for (let xi = begX; xi < endX; ++xi) {
|
|
- const dx = xi * invDeltaX - vx
|
|
|
|
|
|
+ const dx = gridx[xi] - vx
|
|
const xIdx = xi * iuv
|
|
const xIdx = xi * iuv
|
|
for (let yi = begY; yi < endY; ++yi) {
|
|
for (let yi = begY; yi < endY; ++yi) {
|
|
- const dy = yi * invDeltaY - vy
|
|
|
|
|
|
+ const dy = gridy[yi] - vy
|
|
const dxySq = dx * dx + dy * dy
|
|
const dxySq = dx * dx + dy * dy
|
|
const xyIdx = yi * iu + xIdx
|
|
const xyIdx = yi * iu + xIdx
|
|
for (let zi = begZ; zi < endZ; ++zi) {
|
|
for (let zi = begZ; zi < endZ; ++zi) {
|
|
- const dz = zi * invDeltaZ - vz
|
|
|
|
|
|
+ const dz = gridz[zi] - vz
|
|
const dSq = dxySq + dz * dz
|
|
const dSq = dxySq + dz * dz
|
|
if (dSq <= r2sq) {
|
|
if (dSq <= r2sq) {
|
|
const dens = Math.exp(-alpha * (dSq * rSqInv))
|
|
const dens = Math.exp(-alpha * (dSq * rSqInv))
|
|
@@ -118,7 +118,7 @@ export async function GaussianDensityCPU(ctx: RuntimeContext, position: Position
|
|
await ctx.update({ message: 'filling density grid', current: i, max: n })
|
|
await ctx.update({ message: 'filling density grid', current: i, max: n })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- console.timeEnd('gaussian density cpu')
|
|
|
|
|
|
+ // console.timeEnd('gaussian density cpu')
|
|
|
|
|
|
const transform = Mat4.identity()
|
|
const transform = Mat4.identity()
|
|
Mat4.fromScaling(transform, Vec3.inverse(Vec3.zero(), delta))
|
|
Mat4.fromScaling(transform, Vec3.inverse(Vec3.zero(), delta))
|