model.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /**
  2. * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { Model, Structure, StructureSymmetry } from '../../../mol-model/structure';
  7. import { stringToWords } from '../../../mol-util/string';
  8. import { SpacegroupCell } from '../../../mol-math/geometry';
  9. import { ParamDefinition as PD } from '../../../mol-util/param-definition';
  10. import { Vec3 } from '../../../mol-math/linear-algebra';
  11. import { ensureSecondaryStructure } from '../transforms/helpers';
  12. import { RuntimeContext } from '../../../mol-task';
  13. import { PluginContext } from '../../context';
  14. import { Assembly, ModelSymmetry } from '../../../mol-model/structure/model/properties/symmetry';
  15. import { PluginStateObject as SO } from '../objects';
  16. export namespace ModelStructureRepresentation {
  17. export function getParams(model?: Model, defaultValue?: 'deposited' | 'assembly' | 'symmetry' | 'symmetry-mates') {
  18. const assemblyIds = model ? model.symmetry.assemblies.map(a => [a.id, `${a.id}: ${stringToWords(a.details)}`] as [string, string]) : [];
  19. const showSymm = !model ? true : !SpacegroupCell.isZero(model.symmetry.spacegroup.cell);
  20. const modes = {
  21. deposited: PD.EmptyGroup(),
  22. assembly: PD.Group({
  23. id: PD.Optional(model
  24. ? PD.Select(assemblyIds.length ? assemblyIds[0][0] : '', assemblyIds, { label: 'Asm Id', description: 'Assembly Id' })
  25. : PD.Text('', { label: 'Asm Id', description: 'Assembly Id (use empty for the 1st assembly)' }))
  26. }, { isFlat: true }),
  27. 'symmetry-mates': PD.Group({
  28. radius: PD.Numeric(5)
  29. }, { isFlat: true }),
  30. 'symmetry': PD.Group({
  31. ijkMin: PD.Vec3(Vec3.create(-1, -1, -1), { label: 'Min IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } }),
  32. ijkMax: PD.Vec3(Vec3.create(1, 1, 1), { label: 'Max IJK', fieldLabels: { x: 'I', y: 'J', z: 'K' } })
  33. }, { isFlat: true })
  34. };
  35. const options: [keyof typeof modes, string][] = [
  36. ['deposited', 'Deposited']
  37. ];
  38. if (assemblyIds) {
  39. options.push(['assembly', 'Assembly']);
  40. }
  41. if (showSymm) {
  42. options.push(['symmetry-mates', 'Symmetry Mates']);
  43. options.push(['symmetry', 'Symmetry (indices)']);
  44. }
  45. return {
  46. type: PD.MappedStatic(defaultValue || 'deposited', modes, { options })
  47. };
  48. }
  49. export type Params = PD.Values<ReturnType<typeof getParams>>['type']
  50. async function buildAssembly(plugin: PluginContext, ctx: RuntimeContext, model: Model, id?: string) {
  51. let asm: Assembly | undefined = void 0;
  52. // if no id is specified, use the 1st assembly.
  53. if (!id && model.symmetry.assemblies.length !== 0) {
  54. id = model.symmetry.assemblies[0].id;
  55. }
  56. if (model.symmetry.assemblies.length === 0) {
  57. if (id !== 'deposited') {
  58. plugin.log.warn(`Model '${model.entryId}' has no assembly, returning deposited structure.`);
  59. }
  60. } else {
  61. asm = ModelSymmetry.findAssembly(model, id || '');
  62. if (!asm) {
  63. plugin.log.warn(`Model '${model.entryId}' has no assembly called '${id}', returning deposited structure.`);
  64. }
  65. }
  66. const base = Structure.ofModel(model);
  67. if (!asm) {
  68. await ensureSecondaryStructure(base)
  69. const label = { label: 'Deposited', description: Structure.elementDescription(base) };
  70. return new SO.Molecule.Structure(base, label);
  71. }
  72. id = asm.id;
  73. const s = await StructureSymmetry.buildAssembly(base, id!).runInContext(ctx);
  74. await ensureSecondaryStructure(s)
  75. const props = { label: `Assembly ${id}`, description: Structure.elementDescription(s) };
  76. return new SO.Molecule.Structure(s, props);
  77. }
  78. async function buildSymmetry(ctx: RuntimeContext, model: Model, ijkMin: Vec3, ijkMax: Vec3) {
  79. const base = Structure.ofModel(model);
  80. const s = await StructureSymmetry.buildSymmetryRange(base, ijkMin, ijkMax).runInContext(ctx);
  81. await ensureSecondaryStructure(s)
  82. const props = { label: `Symmetry [${ijkMin}] to [${ijkMax}]`, description: Structure.elementDescription(s) };
  83. return new SO.Molecule.Structure(s, props);
  84. }
  85. async function buildSymmetryMates(ctx: RuntimeContext, model: Model, radius: number) {
  86. const base = Structure.ofModel(model);
  87. const s = await StructureSymmetry.builderSymmetryMates(base, radius).runInContext(ctx);
  88. await ensureSecondaryStructure(s)
  89. const props = { label: `Symmetry Mates`, description: Structure.elementDescription(s) };
  90. return new SO.Molecule.Structure(s, props);
  91. }
  92. export async function create(plugin: PluginContext, ctx: RuntimeContext, model: Model, params?: Params): Promise<SO.Molecule.Structure> {
  93. if (!params || params.name === 'deposited') {
  94. const s = Structure.ofModel(model);
  95. await ensureSecondaryStructure(s);
  96. return new SO.Molecule.Structure(s, { label: 'Deposited', description: Structure.elementDescription(s) });
  97. }
  98. if (params.name === 'assembly') {
  99. return buildAssembly(plugin, ctx, model, params.params.id)
  100. }
  101. if (params.name === 'symmetry') {
  102. return buildSymmetry(ctx, model, params.params.ijkMin, params.params.ijkMax)
  103. }
  104. if (params.name === 'symmetry-mates') {
  105. return buildSymmetryMates(ctx, model, params.params.radius)
  106. }
  107. throw new Error(`Unknown represetation type: ${(params as any).name}`);
  108. }
  109. }