Compare commits

...

16 Commits

Author SHA1 Message Date
dsehnal
2c0e7e84da 3.6.2 2022-04-05 17:59:48 +02:00
dsehnal
0d1e105343 changelog 2022-04-05 17:57:14 +02:00
dsehnal
f040c89ab3 React 18 friendly useBehavior hook 2022-04-05 17:51:13 +02:00
David Sehnal
5e9d8298ef Merge pull request #415 from JonStargaryen/master
ModelServer Ligand Export: Fix Alternate Locations & Mismatching Atoms
2022-04-05 17:49:16 +02:00
Sebastian Bittrich
7766ca2793 CHANGELOG 2022-04-04 11:36:39 -07:00
Sebastian Bittrich
fb2f22f120 Merge remote-tracking branch 'upstream/master' 2022-04-04 11:33:01 -07:00
Sebastian Bittrich
146fed3504 CHANGELOG 2022-04-04 11:32:51 -07:00
Sebastian Bittrich
0b7a6e3375 cleanup 2022-04-04 10:55:44 -07:00
Sebastian Bittrich
f1fbdeaca0 handle missing atoms (ignore hydrogen, fail for heavy) 2022-04-04 10:49:40 -07:00
Sebastian Bittrich
ee7e37f6bc handle deuterated part 2 2022-04-04 09:45:42 -07:00
Sebastian Bittrich
861f665ab3 handle deuterated 2022-04-04 09:17:39 -07:00
dsehnal
456de23ad4 remove console.log 2022-04-03 14:45:41 +02:00
dsehnal
6d3578c17e fix alpha orbitals example 2022-04-03 14:08:31 +02:00
Sebastian Bittrich
b87beb4a6e better msg for UNL 2022-04-01 16:58:32 -07:00
Sebastian Bittrich
62a58facb2 better error msg for unknown components 2022-04-01 15:51:00 -07:00
Sebastian Bittrich
5fa8178df7 fix handling of alternate locations in ligand-encoder#_getAtoms 2022-04-01 11:47:59 -07:00
12 changed files with 111 additions and 47 deletions

View File

@@ -6,6 +6,10 @@ Note that since we don't clearly distinguish between a public and private interf
## [Unreleased]
## [v3.6.2] - 2022-04-05
- ModelServer ligand queries: fixes for alternate locations, additional atoms & UNL ligand
- React 18 friendly ``useBehavior`` hook.
## [v3.6.1] - 2022-04-03

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "molstar",
"version": "3.6.1",
"version": "3.6.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "molstar",
"version": "3.6.1",
"version": "3.6.2",
"license": "MIT",
"dependencies": {
"@types/argparse": "^2.0.10",

View File

@@ -1,6 +1,6 @@
{
"name": "molstar",
"version": "3.6.1",
"version": "3.6.2",
"description": "A comprehensive macromolecular library.",
"homepage": "https://github.com/molstar/molstar#readme",
"repository": {

View File

@@ -80,20 +80,24 @@ export class AlphaOrbitalsExample {
this.plugin.managers.interactivity.setProps({ granularity: 'element' });
if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
PluginCommands.Toast.Show(this.plugin, {
title: 'Error',
message: `Browser/device does not support required WebGL extension (OES_texture_float).`
this.plugin.behaviors.canvas3d.initialized.subscribe(init => {
if (!init) return;
if (!canComputeGrid3dOnGPU(this.plugin.canvas3d?.webgl)) {
PluginCommands.Toast.Show(this.plugin, {
title: 'Error',
message: `Browser/device does not support required WebGL extension (OES_texture_float).`
});
return;
}
this.load({
moleculeSdf: DemoMoleculeSDF,
...DemoOrbitals
});
return;
}
this.load({
moleculeSdf: DemoMoleculeSDF,
...DemoOrbitals
mountControls(this, document.getElementById('controls')!);
});
mountControls(this, document.getElementById('controls')!);
}
readonly params = new BehaviorSubject<ParamDefinition.For<Params>>({} as any);

View File

@@ -9,12 +9,14 @@ import { Writer } from './writer';
import { Encoder, Category, Field } from './cif/encoder';
import { ComponentAtom } from '../../mol-model-formats/structure/property/atoms/chem_comp';
import { ComponentBond } from '../../mol-model-formats/structure/property/bonds/chem_comp';
import { getElementIdx, isHydrogen } from '../../mol-model/structure/structure/unit/bonds/common';
import { ElementSymbol } from '../../mol-model/structure/model/types';
interface Atom {
Cartn_x: number,
Cartn_y: number,
Cartn_z: number,
type_symbol: string,
type_symbol: ElementSymbol,
index: number
}
@@ -109,11 +111,12 @@ export abstract class LigandEncoder implements Encoder<string> {
const key = it.move();
const lai = label_atom_id.value(key, data, index) as string;
const ts = type_symbol.value(key, data, index) as string;
if (this.skipHydrogen(ts)) {
index++;
continue;
}
// ignore all alternate locations after the first
if (atoms.has(lai)) continue;
const ts = type_symbol.value(key, data, index) as ElementSymbol;
if (this.skipHydrogen(ts)) continue;
const a: { [k: string]: (string | number) } = {};
for (let _f = 0, _fl = fields.length; _f < _fl; _f++) {
@@ -131,11 +134,15 @@ export abstract class LigandEncoder implements Encoder<string> {
return atoms;
}
protected skipHydrogen(type_symbol: string) {
protected skipHydrogen(type_symbol: ElementSymbol) {
if (this.hydrogens) {
return false;
}
return type_symbol === 'H';
return this.isHydrogen(type_symbol);
}
protected isHydrogen(type_symbol: ElementSymbol) {
return isHydrogen(getElementIdx(type_symbol));
}
private getSortedFields<Ctx>(instance: Category.Instance<Ctx>, names: string[]) {

View File

@@ -26,14 +26,27 @@ export class MolEncoder extends LigandEncoder {
const atomMap = this.componentAtomData.entries.get(name)!;
const bondMap = this.componentBondData.entries.get(name)!;
// happens for the unknown ligands (UNL)
if (!atomMap) throw Error(`The Chemical Component Dictionary doesn't hold any atom data for ${name}`);
let bondCount = 0;
let chiral = false;
// traverse once to determine all actually present atoms
const atoms = this.getAtoms(instance, source);
atoms.forEach((atom1, label_atom_id1) => {
const { index: i1 } = atom1;
const { charge, stereo_config } = atomMap.map.get(label_atom_id1)!;
const { index: i1, type_symbol: type_symbol1 } = atom1;
const atomMapData1 = atomMap.map.get(label_atom_id1);
if (!atomMapData1) {
if (this.isHydrogen(type_symbol1)) {
return;
} else {
throw Error(`Unknown atom ${label_atom_id1} for component ${name}`);
}
}
const { charge, stereo_config } = atomMapData1;
StringBuilder.writePadLeft(ctab, atom1.Cartn_x.toFixed(4), 10);
StringBuilder.writePadLeft(ctab, atom1.Cartn_y.toFixed(4), 10);
StringBuilder.writePadLeft(ctab, atom1.Cartn_z.toFixed(4), 10);
@@ -50,8 +63,8 @@ export class MolEncoder extends LigandEncoder {
const atom2 = atoms.get(label_atom_id2);
if (!atom2) return;
const { index: i2, type_symbol: type_symbol2 } = atom2;
if (i1 < i2 && !this.skipHydrogen(type_symbol2)) {
const { index: i2 } = atom2;
if (i1 < i2) {
const { order } = bond;
StringBuilder.writeIntegerPadLeft(bonds, i1 + 1, 3);
StringBuilder.writeIntegerPadLeft(bonds, i2 + 1, 3);

View File

@@ -29,21 +29,34 @@ export class Mol2Encoder extends LigandEncoder {
const name = this.getName(instance, source);
StringBuilder.writeSafe(this.builder, `# Name: ${name}\n# Created by ${this.encoder}\n\n`);
const atomMap = this.componentAtomData.entries.get(name)!;
const bondMap = this.componentBondData.entries.get(name)!;
// happens for the unknown ligands (UNL)
if (!atomMap) throw Error(`The Chemical Component Dictionary doesn't hold any atom data for ${name}`);
let bondCount = 0;
const atoms = this.getAtoms(instance, source);
StringBuilder.writeSafe(a, '@<TRIPOS>ATOM\n');
StringBuilder.writeSafe(b, '@<TRIPOS>BOND\n');
atoms.forEach((atom1, label_atom_id1) => {
const { index: i1 } = atom1;
const { index: i1, type_symbol: type_symbol1 } = atom1;
const atomMapData1 = atomMap.map.get(label_atom_id1);
if (!atomMapData1) {
if (this.isHydrogen(type_symbol1)) {
return;
} else {
throw Error(`Unknown atom ${label_atom_id1} for component ${name}`);
}
}
if (bondMap?.map) {
bondMap.map.get(label_atom_id1)!.forEach((bond, label_atom_id2) => {
const atom2 = atoms.get(label_atom_id2);
if (!atom2) return;
const { index: i2, type_symbol: type_symbol2 } = atom2;
if (i1 < i2 && !this.skipHydrogen(type_symbol2)) {
const { index: i2 } = atom2;
if (i1 < i2) {
const { order, flags } = bond;
const ar = BondType.is(BondType.Flag.Aromatic, flags);
StringBuilder.writeSafe(b, `${++bondCount} ${i1 + 1} ${i2 + 1} ${ar ? 'ar' : order}`);
@@ -52,7 +65,7 @@ export class Mol2Encoder extends LigandEncoder {
});
}
const sybyl = bondMap?.map ? this.mapToSybyl(label_atom_id1, atom1.type_symbol, bondMap) : atom1.type_symbol;
const sybyl = bondMap?.map ? this.mapToSybyl(label_atom_id1, type_symbol1, bondMap) : type_symbol1;
StringBuilder.writeSafe(a, `${i1 + 1} ${label_atom_id1} ${atom1.Cartn_x.toFixed(3)} ${atom1.Cartn_y.toFixed(3)} ${atom1.Cartn_z.toFixed(3)} ${sybyl} 1 ${name} 0.000\n`);
});

View File

@@ -1,26 +1,23 @@
/**
* Copyright (c) 2020-21 mol* contributors, licensed under MIT, See LICENSE file for more info.
* Copyright (c) 2020-22 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
*/
import { useEffect, useRef, useState } from 'react';
import React from 'react';
import { skip } from 'rxjs';
interface Behavior<T> {
value: T;
subscribe(f: (v: T) => void): { unsubscribe(): void };
}
export function useBehavior<T>(s: Behavior<T>): T;
// eslint-disable-next-line
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined;
// eslint-disable-next-line
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined {
const [, next] = useState({});
const current = useRef<T>();
function useBehaviorLegacy<T>(s: Behavior<T> | undefined): T | undefined {
const [, next] = React.useState({});
const current = React.useRef<T>();
current.current = s?.value;
useEffect(() => {
React.useEffect(() => {
if (!s) {
return;
}
@@ -32,4 +29,29 @@ export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined {
}, [s]);
return s?.value;
}
function useBehaviorReact18<T>(s: Behavior<T> | undefined) {
return (React as any).useSyncExternalStore(
React.useCallback(
(callback: () => void) => {
const sub = (s as any)?.pipe!(skip(1)).subscribe(callback)!;
return () => sub?.unsubscribe();
},
[s]
),
React.useCallback(() => s?.value, [s])
);
}
const _useBehavior = !!(React as any).useSyncExternalStore
? useBehaviorReact18
: useBehaviorLegacy;
export function useBehavior<T>(s: Behavior<T>): T;
// eslint-disable-next-line
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined;
// eslint-disable-next-line
export function useBehavior<T>(s: Behavior<T> | undefined): T | undefined {
return _useBehavior(s);
}

View File

@@ -80,9 +80,6 @@ export async function getContourLevelEmdb(plugin: PluginContext, taskCtx: Runtim
}
}
const contourLevel = parseFloat(primaryContour.getElementsByTagName('level')[0].textContent!);
console.log({ contourLevel });
return contourLevel;
}

View File

@@ -1,3 +1,9 @@
# 0.9.9
* /ligand queries: fix behavior for alternate locations
* /ligand queries: handle additional atoms more gracefully
* /ligand queries: better error message for UNL
* /ligand queries: treat deuterium/tritium as hydrogen
# 0.9.8
* fix support for chem_comp_bond and struct_conn categories

View File

@@ -237,10 +237,8 @@ async function resolveJobEntry(entry: JobEntry, structure: StructureWrapper, enc
encoder.writeCategory(_model_server_params, entry);
if (entry.queryDefinition.niceName === 'Ligand') {
if (encoder instanceof MolEncoder) {
encoder.setComponentAtomData(ComponentAtom.Provider.get(structure.models[0])!);
}
if (encoder instanceof MolEncoder || encoder instanceof Mol2Encoder) {
encoder.setComponentAtomData(ComponentAtom.Provider.get(structure.models[0])!);
encoder.setComponentBondData(ComponentBond.Provider.get(structure.models[0])!);
}
}

View File

@@ -4,4 +4,4 @@
* @author David Sehnal <david.sehnal@gmail.com>
*/
export const VERSION = '0.9.8';
export const VERSION = '0.9.9';