Skip to content
Snippets Groups Projects
Commit 7a13668e authored by David Sehnal's avatar David Sehnal
Browse files

Better symmetry mate generation

parent 7be64c0d
No related branches found
No related tags found
No related merge requests found
...@@ -44,7 +44,10 @@ export namespace Assembly { ...@@ -44,7 +44,10 @@ export namespace Assembly {
interface ModelSymmetry { interface ModelSymmetry {
readonly assemblies: ReadonlyArray<Assembly>, readonly assemblies: ReadonlyArray<Assembly>,
readonly spacegroup: Spacegroup, readonly spacegroup: Spacegroup,
readonly isNonStandardCrytalFrame: boolean readonly isNonStandardCrytalFrame: boolean,
// optionally cached operators from [-3, -3, -3] to [3, 3, 3]
_operators_333?: SymmetryOperator[]
} }
namespace ModelSymmetry { namespace ModelSymmetry {
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
import Structure from './structure' import Structure from './structure'
import { Selection } from '../query' import { Selection } from '../query'
import { ModelSymmetry } from '../model' import { ModelSymmetry } from '../model'
import { Task } from 'mol-task'; import { Task, RuntimeContext } from 'mol-task';
import { SortedArray } from 'mol-data/int'; import { SortedArray } from 'mol-data/int';
import Unit from './unit'; import Unit from './unit';
import { EquivalenceClasses, hash2 } from 'mol-data/util'; import { EquivalenceClasses, hash2 } from 'mol-data/util';
...@@ -44,41 +44,11 @@ namespace StructureSymmetry { ...@@ -44,41 +44,11 @@ namespace StructureSymmetry {
} }
export function builderSymmetryMates(structure: Structure, radius: number) { export function builderSymmetryMates(structure: Structure, radius: number) {
// TODO: do it properly return Task.create('Find Symmetry Mates', ctx => findMatesRadius(ctx, structure, radius));
return buildSymmetryRange(structure, Vec3.create(-3, -3, -3), Vec3.create(3, 3, 3));
} }
export function buildSymmetryRange(structure: Structure, ijkMin: Vec3, ijkMax: Vec3) { export function buildSymmetryRange(structure: Structure, ijkMin: Vec3, ijkMax: Vec3) {
return Task.create('Build Assembly', async ctx => { return Task.create('Build Symmetry', ctx => findSymmetryRange(ctx, structure, ijkMin, ijkMax));
const models = Structure.getModels(structure);
if (models.length !== 1) throw new Error('Can only build symmetries from structures based on 1 model.');
const { spacegroup } = models[0].symmetry;
if (SpacegroupCell.isZero(spacegroup.cell)) return structure;
const operators: SymmetryOperator[] = [];
for (let op = 0; op < spacegroup.operators.length; op++) {
for (let i = ijkMin[0]; i < ijkMax[0]; i++) {
for (let j = ijkMin[1]; j < ijkMax[1]; j++) {
for (let k = ijkMin[2]; k < ijkMax[2]; k++) {
operators[operators.length] = Spacegroup.getSymmetryOperator(spacegroup, op, i, j, k);
}
}
}
}
const assembler = Structure.Builder();
const { units } = structure;
for (const oper of operators) {
for (const unit of units) {
assembler.addWithOperator(unit, oper);
}
}
return assembler.getStructure();
});
} }
function hashUnit(u: Unit) { function hashUnit(u: Unit) {
...@@ -107,4 +77,81 @@ namespace StructureSymmetry { ...@@ -107,4 +77,81 @@ namespace StructureSymmetry {
} }
} }
function getOperators(symmetry: ModelSymmetry, ijkMin: Vec3, ijkMax: Vec3) {
const operators: SymmetryOperator[] = symmetry._operators_333 || [];
const { spacegroup } = symmetry;
if (operators.length === 0) {
operators[0] = Spacegroup.getSymmetryOperator(spacegroup, 0, 0, 0, 0)
for (let op = 0; op < spacegroup.operators.length; op++) {
for (let i = ijkMin[0]; i < ijkMax[0]; i++) {
for (let j = ijkMin[1]; j < ijkMax[1]; j++) {
for (let k = ijkMin[2]; k < ijkMax[2]; k++) {
// we have added identity as the 1st operator.
if (op === 0 && i === 0 && j === 0 && k === 0) continue;
operators[operators.length] = Spacegroup.getSymmetryOperator(spacegroup, op, i, j, k);
}
}
}
}
symmetry._operators_333 = operators;
}
return operators;
}
async function findSymmetryRange(ctx: RuntimeContext, structure: Structure, ijkMin: Vec3, ijkMax: Vec3) {
const models = Structure.getModels(structure);
if (models.length !== 1) throw new Error('Can only build symmetries from structures based on 1 model.');
const { spacegroup } = models[0].symmetry;
if (SpacegroupCell.isZero(spacegroup.cell)) return structure;
const operators = getOperators(models[0].symmetry, ijkMin, ijkMax);
const assembler = Structure.Builder();
const { units } = structure;
for (const oper of operators) {
for (const unit of units) {
assembler.addWithOperator(unit, oper);
}
if (ctx.shouldUpdate) await ctx.update('Building symmetry...');
}
return assembler.getStructure();
}
async function findMatesRadius(ctx: RuntimeContext, structure: Structure, radius: number) {
const models = Structure.getModels(structure);
if (models.length !== 1) throw new Error('Can only build symmetries from structures based on 1 model.');
const symmetry = models[0].symmetry;
const { spacegroup } = symmetry;
if (SpacegroupCell.isZero(spacegroup.cell)) return structure;
if (ctx.shouldUpdate) await ctx.update('Initialing...');
const operators = getOperators(symmetry, Vec3.create(-3, -3, -3), Vec3.create(3, 3, 3));
const lookup = structure.lookup3d;
const assembler = Structure.Builder();
const { units } = structure;
const center = Vec3.zero();
for (const oper of operators) {
for (const unit of units) {
const boundingSphere = unit.lookup3d.boundary.sphere;
Vec3.transformMat4(center, boundingSphere.center, oper.matrix);
const closeUnits = lookup.findUnitIndices(center[0], center[1], center[2], boundingSphere.radius + radius);
for (let uI = 0, _uI = closeUnits.count; uI < _uI; uI++) {
const closeUnit = units[closeUnits.indices[uI]];
if (!closeUnit.lookup3d.check(center[0], center[1], center[2], boundingSphere.radius + radius)) continue;
assembler.addWithOperator(unit, oper);
}
}
if (ctx.shouldUpdate) await ctx.update('Building symmetry...');
}
return assembler.getStructure();
}
export default StructureSymmetry; export default StructureSymmetry;
\ No newline at end of file
...@@ -133,9 +133,9 @@ function abortTree(root: Progress.Node) { ...@@ -133,9 +133,9 @@ function abortTree(root: Progress.Node) {
for (const c of root.children) abortTree(c); for (const c of root.children) abortTree(c);
} }
function shouldNotify(info: ProgressInfo, time: number) { // function shouldNotify(info: ProgressInfo, time: number) {
return time - info.lastNotified > info.updateRateMs; // return time - info.lastNotified > info.updateRateMs;
} // }
function notifyObserver(info: ProgressInfo, time: number) { function notifyObserver(info: ProgressInfo, time: number) {
info.lastNotified = time; info.lastNotified = time;
...@@ -194,6 +194,7 @@ class ObservableRuntimeContext implements RuntimeContext { ...@@ -194,6 +194,7 @@ class ObservableRuntimeContext implements RuntimeContext {
this.lastUpdatedTime = now(); this.lastUpdatedTime = now();
this.updateProgress(progress); this.updateProgress(progress);
// TODO: do the shouldNotify check here?
if (!!dontNotify /*|| !shouldNotify(this.info, this.lastUpdatedTime)*/) return; if (!!dontNotify /*|| !shouldNotify(this.info, this.lastUpdatedTime)*/) return;
notifyObserver(this.info, this.lastUpdatedTime); notifyObserver(this.info, this.lastUpdatedTime);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment