volume.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. /**
  2. * Copyright (c) 2018-2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. * @author Alexander Rose <alexander.rose@weirdbyte.de>
  6. */
  7. import { VolumeIsoValue } from '../../../mol-model/volume';
  8. import { PluginContext } from '../../../mol-plugin/context';
  9. import { State, StateAction, StateBuilder, StateTransformer } from '../../../mol-state';
  10. import { Task } from '../../../mol-task';
  11. import { ColorNames } from '../../../mol-util/color/tables';
  12. import { FileInfo, getFileInfo } from '../../../mol-util/file-info';
  13. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  14. import { PluginStateObject } from '../objects';
  15. import { StateTransforms } from '../transforms';
  16. import { Download } from '../transforms/data';
  17. import { VolumeRepresentation3DHelpers } from '../transforms/representation';
  18. import { DataFormatProvider, guessCifVariant, DataFormatBuilderOptions } from './data-format';
  19. export const Ccp4Provider: DataFormatProvider<any> = {
  20. label: 'CCP4/MRC/BRIX',
  21. description: 'CCP4/MRC/BRIX',
  22. stringExtensions: [],
  23. binaryExtensions: ['ccp4', 'mrc', 'map'],
  24. isApplicable: (info: FileInfo, data: Uint8Array) => {
  25. return info.ext === 'ccp4' || info.ext === 'mrc' || info.ext === 'map'
  26. },
  27. getDefaultBuilder: (ctx: PluginContext, data: StateBuilder.To<PluginStateObject.Data.Binary>, options: DataFormatBuilderOptions, state: State) => {
  28. return Task.create('CCP4/MRC/BRIX default builder', async taskCtx => {
  29. let tree: StateBuilder.To<any> = data.apply(StateTransforms.Data.ParseCcp4)
  30. .apply(StateTransforms.Volume.VolumeFromCcp4)
  31. if (options.visuals) {
  32. tree = tree.apply(StateTransforms.Representation.VolumeRepresentation3D)
  33. }
  34. await state.updateTree(tree).runInContext(taskCtx)
  35. })
  36. }
  37. }
  38. export const Dsn6Provider: DataFormatProvider<any> = {
  39. label: 'DSN6/BRIX',
  40. description: 'DSN6/BRIX',
  41. stringExtensions: [],
  42. binaryExtensions: ['dsn6', 'brix'],
  43. isApplicable: (info: FileInfo, data: Uint8Array) => {
  44. return info.ext === 'dsn6' || info.ext === 'brix'
  45. },
  46. getDefaultBuilder: (ctx: PluginContext, data: StateBuilder.To<PluginStateObject.Data.Binary>, options: DataFormatBuilderOptions, state: State) => {
  47. return Task.create('DSN6/BRIX default builder', async taskCtx => {
  48. let tree: StateBuilder.To<any> = data.apply(StateTransforms.Data.ParseDsn6)
  49. .apply(StateTransforms.Volume.VolumeFromDsn6)
  50. if (options.visuals) {
  51. tree = tree.apply(StateTransforms.Representation.VolumeRepresentation3D)
  52. }
  53. await state.updateTree(tree).runInContext(taskCtx)
  54. })
  55. }
  56. }
  57. export const DscifProvider: DataFormatProvider<any> = {
  58. label: 'DensityServer CIF',
  59. description: 'DensityServer CIF',
  60. stringExtensions: ['cif'],
  61. binaryExtensions: ['bcif'],
  62. isApplicable: (info: FileInfo, data: Uint8Array | string) => {
  63. return guessCifVariant(info, data) === 'dscif' ? true : false
  64. },
  65. getDefaultBuilder: (ctx: PluginContext, data: StateBuilder.To<PluginStateObject.Data.Binary | PluginStateObject.Data.String>, options: DataFormatBuilderOptions, state: State) => {
  66. return Task.create('DensityServer CIF default builder', async taskCtx => {
  67. const cifBuilder = data.apply(StateTransforms.Data.ParseCif)
  68. const cifStateObject = await state.updateTree(cifBuilder).runInContext(taskCtx)
  69. const b = state.build().to(cifBuilder.ref);
  70. const blocks = cifStateObject.data.blocks.slice(1); // zero block contains query meta-data
  71. let tree: StateBuilder.To<any>
  72. if (blocks.length === 1) {
  73. tree = b
  74. .apply(StateTransforms.Volume.VolumeFromDensityServerCif, { blockHeader: blocks[0].header })
  75. if (options.visuals) {
  76. tree = tree.apply(StateTransforms.Representation.VolumeRepresentation3D, VolumeRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'isosurface', { isoValue: VolumeIsoValue.relative(1.5), alpha: 0.3 }, 'uniform', { value: ColorNames.teal }))
  77. }
  78. } else if (blocks.length === 2) {
  79. tree = b
  80. .apply(StateTransforms.Volume.VolumeFromDensityServerCif, { blockHeader: blocks[0].header })
  81. if (options.visuals) {
  82. tree = tree.apply(StateTransforms.Representation.VolumeRepresentation3D, VolumeRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'isosurface', { isoValue: VolumeIsoValue.relative(1.5), alpha: 0.3 }, 'uniform', { value: ColorNames.blue }))
  83. }
  84. const vol = tree.to(cifBuilder.ref)
  85. .apply(StateTransforms.Volume.VolumeFromDensityServerCif, { blockHeader: blocks[1].header })
  86. const posParams = VolumeRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'isosurface', { isoValue: VolumeIsoValue.relative(3), alpha: 0.3 }, 'uniform', { value: ColorNames.green })
  87. tree = vol.apply(StateTransforms.Representation.VolumeRepresentation3D, posParams)
  88. const negParams = VolumeRepresentation3DHelpers.getDefaultParamsStatic(ctx, 'isosurface', { isoValue: VolumeIsoValue.relative(-3), alpha: 0.3 }, 'uniform', { value: ColorNames.red })
  89. tree = tree.to(vol.ref).apply(StateTransforms.Representation.VolumeRepresentation3D, negParams)
  90. } else {
  91. throw new Error('unknown number of blocks')
  92. }
  93. await state.updateTree(tree).runInContext(taskCtx);
  94. })
  95. }
  96. }
  97. export { DownloadDensity };
  98. type DownloadDensity = typeof DownloadDensity
  99. const DownloadDensity = StateAction.build({
  100. from: PluginStateObject.Root,
  101. display: { name: 'Download Density', description: 'Load a density from the provided source and create its default visual.' },
  102. params: (a, ctx: PluginContext) => {
  103. const { options } = ctx.dataFormat.registry
  104. return {
  105. source: PD.MappedStatic('rcsb', {
  106. 'pdbe': PD.Group({
  107. id: PD.Text('1tqn', { label: 'Id' }),
  108. type: PD.Select('2fofc', [['2fofc', '2Fo-Fc'], ['fofc', 'Fo-Fc']]),
  109. }, { isFlat: true }),
  110. 'pdbe-emd-ds': PD.Group({
  111. id: PD.Text('emd-8004', { label: 'Id' }),
  112. detail: PD.Numeric(3, { min: 0, max: 10, step: 1 }, { label: 'Detail' }),
  113. }, { isFlat: true }),
  114. 'pdbe-xray-ds': PD.Group({
  115. id: PD.Text('1tqn', { label: 'Id' }),
  116. detail: PD.Numeric(3, { min: 0, max: 10, step: 1 }, { label: 'Detail' }),
  117. }, { isFlat: true }),
  118. 'rcsb': PD.Group({
  119. id: PD.Text('1tqn', { label: 'Id' }),
  120. type: PD.Select('2fofc', [['2fofc', '2Fo-Fc'], ['fofc', 'Fo-Fc']]),
  121. }, { isFlat: true }),
  122. 'url': PD.Group({
  123. url: PD.Text(''),
  124. isBinary: PD.Boolean(false),
  125. format: PD.Select('auto', options),
  126. }, { isFlat: true })
  127. }, {
  128. options: [
  129. ['pdbe', 'PDBe X-ray maps'],
  130. ['pdbe-emd-ds', 'PDBe EMD Density Server'],
  131. ['pdbe-xray-ds', 'PDBe X-ray Density Server'],
  132. ['rcsb', 'RCSB X-ray maps'],
  133. ['url', 'URL']
  134. ]
  135. })
  136. }
  137. }
  138. })(({ params, state }, ctx: PluginContext) => Task.create('Download Density', async taskCtx => {
  139. const src = params.source;
  140. let downloadParams: StateTransformer.Params<Download>;
  141. let provider: DataFormatProvider<any>
  142. switch (src.name) {
  143. case 'url':
  144. downloadParams = src.params;
  145. break;
  146. case 'pdbe':
  147. downloadParams = {
  148. url: src.params.type === '2fofc'
  149. ? `http://www.ebi.ac.uk/pdbe/coordinates/files/${src.params.id.toLowerCase()}.ccp4`
  150. : `http://www.ebi.ac.uk/pdbe/coordinates/files/${src.params.id.toLowerCase()}_diff.ccp4`,
  151. isBinary: true,
  152. label: `PDBe X-ray map: ${src.params.id}`
  153. };
  154. break;
  155. case 'pdbe-emd-ds':
  156. downloadParams = {
  157. url: `https://www.ebi.ac.uk/pdbe/densities/emd/${src.params.id.toLowerCase()}/cell?detail=${src.params.detail}`,
  158. isBinary: true,
  159. label: `PDBe EMD Density Server: ${src.params.id}`
  160. };
  161. break;
  162. case 'pdbe-xray-ds':
  163. downloadParams = {
  164. url: `https://www.ebi.ac.uk/pdbe/densities/x-ray/${src.params.id.toLowerCase()}/cell?detail=${src.params.detail}`,
  165. isBinary: true,
  166. label: `PDBe X-ray Density Server: ${src.params.id}`
  167. };
  168. break;
  169. case 'rcsb':
  170. downloadParams = {
  171. url: src.params.type === '2fofc'
  172. ? `https://edmaps.rcsb.org/maps/${src.params.id.toLowerCase()}_2fofc.dsn6`
  173. : `https://edmaps.rcsb.org/maps/${src.params.id.toLowerCase()}_fofc.dsn6`,
  174. isBinary: true,
  175. label: `RCSB X-ray map: ${src.params.id}`
  176. };
  177. break;
  178. default: throw new Error(`${(src as any).name} not supported.`);
  179. }
  180. const data = state.build().toRoot().apply(StateTransforms.Data.Download, downloadParams);
  181. const dataStateObject = await state.updateTree(data).runInContext(taskCtx);
  182. switch (src.name) {
  183. case 'url':
  184. downloadParams = src.params;
  185. provider = src.params.format === 'auto' ? ctx.dataFormat.registry.auto(getFileInfo(downloadParams.url), dataStateObject) : ctx.dataFormat.registry.get(src.params.format)
  186. break;
  187. case 'pdbe':
  188. provider = ctx.dataFormat.registry.get('ccp4')
  189. break;
  190. case 'pdbe-emd-ds':
  191. case 'pdbe-xray-ds':
  192. provider = ctx.dataFormat.registry.get('dscif')
  193. break;
  194. case 'rcsb':
  195. provider = ctx.dataFormat.registry.get('dsn6')
  196. break;
  197. default: throw new Error(`${(src as any).name} not supported.`);
  198. }
  199. const b = state.build().to(data.ref);
  200. await provider.getDefaultBuilder(ctx, b, { visuals: true }, state).runInContext(taskCtx)
  201. }));