|
@@ -1,5 +1,5 @@
|
|
|
/**
|
|
|
- * Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
+ * Copyright (c) 2018-2021 mol* contributors, licensed under MIT, See LICENSE file for more info.
|
|
|
*
|
|
|
* @author David Sehnal <david.sehnal@gmail.com>
|
|
|
* @author Alexander Rose <alexander.rose@weirdbyte.de>
|
|
@@ -18,19 +18,23 @@ import { Download } from '../transforms/data';
|
|
|
import { CustomModelProperties, CustomStructureProperties, TrajectoryFromModelAndCoordinates } from '../transforms/model';
|
|
|
import { Asset } from '../../mol-util/assets';
|
|
|
import { PluginConfig } from '../../mol-plugin/config';
|
|
|
+import { getFileInfo } from '../../mol-util/file-info';
|
|
|
|
|
|
-const DownloadModelRepresentationOptions = (plugin: PluginContext) => PD.Group({
|
|
|
- type: RootStructureDefinition.getParams(void 0, 'auto').type,
|
|
|
- representation: PD.Select(PresetStructureRepresentations.auto.id,
|
|
|
- plugin.builders.structure.representation.getPresets().map(p => [p.id, p.display.name, p.display.group] as any),
|
|
|
- { description: 'Which representation preset to use.' }),
|
|
|
- representationParams: PD.Group(StructureRepresentationPresetProvider.CommonParams, { isHidden: true }),
|
|
|
- asTrajectory: PD.Optional(PD.Boolean(false, { description: 'Load all entries into a single trajectory.' }))
|
|
|
-}, { isExpanded: false });
|
|
|
+const DownloadModelRepresentationOptions = (plugin: PluginContext) => {
|
|
|
+ const representationDefault = plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
|
|
|
+ return PD.Group({
|
|
|
+ type: RootStructureDefinition.getParams(void 0, 'auto').type,
|
|
|
+ representation: PD.Select(representationDefault,
|
|
|
+ plugin.builders.structure.representation.getPresets().map(p => [p.id, p.display.name, p.display.group] as any),
|
|
|
+ { description: 'Which representation preset to use.' }),
|
|
|
+ representationParams: PD.Group(StructureRepresentationPresetProvider.CommonParams, { isHidden: true }),
|
|
|
+ asTrajectory: PD.Optional(PD.Boolean(false, { description: 'Load all entries into a single trajectory.' }))
|
|
|
+ }, { isExpanded: false });
|
|
|
+};
|
|
|
|
|
|
export const PdbDownloadProvider = {
|
|
|
'rcsb': PD.Group({
|
|
|
- encoding: PD.Select('bcif', [['cif', 'cif'], ['bcif', 'bcif']] as ['cif' | 'bcif', string][]),
|
|
|
+ encoding: PD.Select('bcif', PD.arrayToOptions(['cif', 'bcif'] as const)),
|
|
|
}, { label: 'RCSB PDB', isFlat: true }),
|
|
|
'pdbe': PD.Group({
|
|
|
variant: PD.Select('updated-bcif', [['updated-bcif', 'Updated (bcif)'], ['updated', 'Updated'], ['archival', 'Archival']] as ['updated' | 'updtaed-bcif' | 'archival', string][]),
|
|
@@ -58,7 +62,7 @@ const DownloadStructure = StateAction.build({
|
|
|
'pdb-dev': PD.Group({
|
|
|
provider: PD.Group({
|
|
|
id: PD.Text('PDBDEV_00000001', { label: 'PDBDev Id(s)', description: 'One or more comma/space separated ids.' }),
|
|
|
- encoding: PD.Select('bcif', [['cif', 'cif'], ['bcif', 'bcif']] as ['cif' | 'bcif', string][]),
|
|
|
+ encoding: PD.Select('bcif', PD.arrayToOptions(['cif', 'bcif'] as const)),
|
|
|
}, { pivot: 'id' }),
|
|
|
options
|
|
|
}, { isFlat: true, label: 'PDBDEV' }),
|
|
@@ -66,6 +70,14 @@ const DownloadStructure = StateAction.build({
|
|
|
id: PD.Text('Q9Y2I8', { label: 'UniProtKB AC(s)', description: 'One or more comma/space separated ACs.' }),
|
|
|
options
|
|
|
}, { isFlat: true, label: 'SWISS-MODEL', description: 'Loads the best homology model or experimental structure' }),
|
|
|
+ 'alphafolddb': PD.Group({
|
|
|
+ id: PD.Text('Q8W3K0', { label: 'UniProtKB AC(s)', description: 'One or more comma/space separated ACs.' }),
|
|
|
+ options
|
|
|
+ }, { isFlat: true, label: 'AlphaFold DB', description: 'Loads the predicted model if available' }),
|
|
|
+ 'modelarchive': PD.Group({
|
|
|
+ id: PD.Text('ma-bak-cepc-0003', { label: 'Accession Code(s)', description: 'One or more comma/space separated ACs.' }),
|
|
|
+ options
|
|
|
+ }, { isFlat: true, label: 'Model Archive' }),
|
|
|
'pubchem': PD.Group({
|
|
|
id: PD.Text('2244,2245', { label: 'PubChem ID', description: 'One or more comma/space separated IDs.' }),
|
|
|
options
|
|
@@ -84,7 +96,7 @@ const DownloadStructure = StateAction.build({
|
|
|
|
|
|
const src = params.source;
|
|
|
let downloadParams: StateTransformer.Params<Download>[];
|
|
|
- let asTrajectory = false, format: BuiltInTrajectoryFormat = 'mmcif';
|
|
|
+ let asTrajectory = false, format: BuiltInTrajectoryFormat | 'auto' = 'mmcif';
|
|
|
|
|
|
switch (src.name) {
|
|
|
case 'url':
|
|
@@ -92,7 +104,7 @@ const DownloadStructure = StateAction.build({
|
|
|
format = src.params.format;
|
|
|
break;
|
|
|
case 'pdb':
|
|
|
- downloadParams = src.params.provider.server.name === 'pdbe'
|
|
|
+ downloadParams = await (src.params.provider.server.name === 'pdbe'
|
|
|
? src.params.provider.server.params.variant === 'updated'
|
|
|
? getDownloadParams(src.params.provider.id, id => `https://www.ebi.ac.uk/pdbe/static/entry/${id.toLowerCase()}_updated.cif`, id => `PDBe: ${id} (updated cif)`, false)
|
|
|
: src.params.provider.server.params.variant === 'updated-bcif'
|
|
@@ -100,11 +112,12 @@ const DownloadStructure = StateAction.build({
|
|
|
: getDownloadParams(src.params.provider.id, id => `https://www.ebi.ac.uk/pdbe/static/entry/${id.toLowerCase()}.cif`, id => `PDBe: ${id} (cif)`, false)
|
|
|
: src.params.provider.server.params.encoding === 'cif'
|
|
|
? getDownloadParams(src.params.provider.id, id => `https://files.rcsb.org/download/${id.toUpperCase()}.cif`, id => `RCSB: ${id} (cif)`, false)
|
|
|
- : getDownloadParams(src.params.provider.id, id => `https://models.rcsb.org/${id.toUpperCase()}.bcif`, id => `RCSB: ${id} (bcif)`, true);
|
|
|
+ : getDownloadParams(src.params.provider.id, id => `https://models.rcsb.org/${id.toUpperCase()}.bcif`, id => `RCSB: ${id} (bcif)`, true)
|
|
|
+ );
|
|
|
asTrajectory = !!src.params.options.asTrajectory;
|
|
|
break;
|
|
|
case 'pdb-dev':
|
|
|
- downloadParams = getDownloadParams(src.params.provider.id,
|
|
|
+ downloadParams = await getDownloadParams(src.params.provider.id,
|
|
|
id => {
|
|
|
const nId = id.toUpperCase().startsWith('PDBDEV_') ? id : `PDBDEV_${id.padStart(8, '0')}`;
|
|
|
return src.params.provider.encoding === 'bcif'
|
|
@@ -117,19 +130,34 @@ const DownloadStructure = StateAction.build({
|
|
|
asTrajectory = !!src.params.options.asTrajectory;
|
|
|
break;
|
|
|
case 'swissmodel':
|
|
|
- downloadParams = getDownloadParams(src.params.id, id => `https://swissmodel.expasy.org/repository/uniprot/${id.toUpperCase()}.pdb`, id => `SWISS-MODEL: ${id}`, false);
|
|
|
+ downloadParams = await getDownloadParams(src.params.id, id => `https://swissmodel.expasy.org/repository/uniprot/${id.toUpperCase()}.pdb`, id => `SWISS-MODEL: ${id}`, false);
|
|
|
asTrajectory = !!src.params.options.asTrajectory;
|
|
|
format = 'pdb';
|
|
|
break;
|
|
|
+ case 'alphafolddb':
|
|
|
+ downloadParams = await getDownloadParams(src.params.id, async id => {
|
|
|
+ const url = `https://www.alphafold.ebi.ac.uk/api/prediction/${id.toUpperCase()}`;
|
|
|
+ const info = await plugin.runTask(plugin.fetch({ url, type: 'json' }));
|
|
|
+ if (Array.isArray(info) && info.length > 0) return info[0].cifUrl;
|
|
|
+ throw new Error(`No AlphaFold DB entry for '${id}'`);
|
|
|
+ }, id => `AlphaFold DB: ${id}`, false);
|
|
|
+ asTrajectory = !!src.params.options.asTrajectory;
|
|
|
+ format = 'mmcif';
|
|
|
+ break;
|
|
|
+ case 'modelarchive':
|
|
|
+ downloadParams = await getDownloadParams(src.params.id, id => `https://www.modelarchive.org/doi/10.5452/${id.toLowerCase()}.cif`, id => `Model Archive: ${id}`, false);
|
|
|
+ asTrajectory = !!src.params.options.asTrajectory;
|
|
|
+ format = 'mmcif';
|
|
|
+ break;
|
|
|
case 'pubchem':
|
|
|
- downloadParams = getDownloadParams(src.params.id, id => `https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/CID/${id.trim()}/record/SDF/?record_type=3d`, id => `PubChem: ${id}`, false);
|
|
|
+ downloadParams = await getDownloadParams(src.params.id, id => `https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/CID/${id.trim()}/record/SDF/?record_type=3d`, id => `PubChem: ${id}`, false);
|
|
|
asTrajectory = !!src.params.options.asTrajectory;
|
|
|
format = 'mol';
|
|
|
break;
|
|
|
default: throw new Error(`${(src as any).name} not supported.`);
|
|
|
}
|
|
|
|
|
|
- const representationPreset: any = params.source.params.options.representation || PresetStructureRepresentations.auto.id;
|
|
|
+ const representationPreset: any = params.source.params.options.representation || plugin.config.get(PluginConfig.Structure.DefaultRepresentationPreset) || PresetStructureRepresentations.auto.id;
|
|
|
const showUnitcell = representationPreset !== PresetStructureRepresentations.empty.id;
|
|
|
|
|
|
const structure = src.params.options.type.name === 'auto' ? void 0 : src.params.options.type;
|
|
@@ -151,7 +179,11 @@ const DownloadStructure = StateAction.build({
|
|
|
} else {
|
|
|
for (const download of downloadParams) {
|
|
|
const data = await plugin.builders.data.download(download, { state: { isGhost: true } });
|
|
|
- const trajectory = await plugin.builders.structure.parseTrajectory(data, format);
|
|
|
+ const provider = format === 'auto'
|
|
|
+ ? plugin.dataFormats.auto(getFileInfo(Asset.getUrl(download.url)), data.cell?.obj!)
|
|
|
+ : plugin.dataFormats.get(format);
|
|
|
+ if (!provider) throw new Error('unknown file format');
|
|
|
+ const trajectory = await plugin.builders.structure.parseTrajectory(data, provider);
|
|
|
|
|
|
await plugin.builders.structure.hierarchy.applyPreset(trajectory, 'default', {
|
|
|
structure,
|
|
@@ -164,11 +196,11 @@ const DownloadStructure = StateAction.build({
|
|
|
}).runInContext(ctx);
|
|
|
}));
|
|
|
|
|
|
-function getDownloadParams(src: string, url: (id: string) => string, label: (id: string) => string, isBinary: boolean): StateTransformer.Params<Download>[] {
|
|
|
+async function getDownloadParams(src: string, url: (id: string) => string | Promise<string>, label: (id: string) => string, isBinary: boolean): Promise<StateTransformer.Params<Download>[]> {
|
|
|
const ids = src.split(/[,\s]/).map(id => id.trim()).filter(id => !!id && (id.length >= 4 || /^[1-9][0-9]*$/.test(id)));
|
|
|
const ret: StateTransformer.Params<Download>[] = [];
|
|
|
for (const id of ids) {
|
|
|
- ret.push({ url: Asset.Url(url(id)), isBinary, label: label(id) });
|
|
|
+ ret.push({ url: Asset.Url(await url(id)), isBinary, label: label(id) });
|
|
|
}
|
|
|
return ret;
|
|
|
}
|
|
@@ -176,7 +208,7 @@ function getDownloadParams(src: string, url: (id: string) => string, label: (id:
|
|
|
export const UpdateTrajectory = StateAction.build({
|
|
|
display: { name: 'Update Trajectory' },
|
|
|
params: {
|
|
|
- action: PD.Select<'advance' | 'reset'>('advance', [['advance', 'Advance'], ['reset', 'Reset']]),
|
|
|
+ action: PD.Select('advance', PD.arrayToOptions(['advance', 'reset'] as const)),
|
|
|
by: PD.Optional(PD.Numeric(1, { min: -1, max: 1, step: 1 }))
|
|
|
}
|
|
|
})(({ params, state }) => {
|