symmetry.ts 4.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /**
  2. * Copyright (c) 2017-2020 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 { mmCIF_Schema } from '../../../mol-io/reader/cif/schema/mmcif';
  8. import { Spacegroup, SpacegroupCell, SymmetryOperator } from '../../../mol-math/geometry';
  9. import { Tensor, Vec3, Mat3 } from '../../../mol-math/linear-algebra';
  10. import { Symmetry } from '../../../mol-model/structure/model/properties/symmetry';
  11. import { createAssemblies } from './assembly';
  12. import { CustomPropertyDescriptor } from '../../../mol-model/custom-property';
  13. import { FormatPropertyProvider } from '../common/property';
  14. import { Table } from '../../../mol-data/db';
  15. export { ModelSymmetry };
  16. namespace ModelSymmetry {
  17. export const Descriptor: CustomPropertyDescriptor = {
  18. name: 'model_symmetry',
  19. };
  20. export const Provider = FormatPropertyProvider.create<Symmetry>(Descriptor);
  21. type Data = {
  22. symmetry: Table<mmCIF_Schema['symmetry']>
  23. cell: Table<mmCIF_Schema['cell']>
  24. struct_ncs_oper: Table<mmCIF_Schema['struct_ncs_oper']>
  25. atom_sites: Table<mmCIF_Schema['atom_sites']>
  26. pdbx_struct_assembly: Table<mmCIF_Schema['pdbx_struct_assembly']>
  27. pdbx_struct_assembly_gen: Table<mmCIF_Schema['pdbx_struct_assembly_gen']>
  28. pdbx_struct_oper_list: Table<mmCIF_Schema['pdbx_struct_oper_list']>
  29. }
  30. export function fromData(data: Data): Symmetry {
  31. const assemblies = createAssemblies(data.pdbx_struct_assembly, data.pdbx_struct_assembly_gen, data.pdbx_struct_oper_list);
  32. const spacegroup = getSpacegroup(data.symmetry, data.cell);
  33. const isNonStandardCrystalFrame = checkNonStandardCrystalFrame(data.atom_sites, spacegroup);
  34. return { assemblies, spacegroup, isNonStandardCrystalFrame, ncsOperators: getNcsOperators(data.struct_ncs_oper) };
  35. }
  36. export function fromCell(size: Vec3, anglesInRadians: Vec3): Symmetry {
  37. const spaceCell = SpacegroupCell.create('P 1', size, anglesInRadians);
  38. const spacegroup = Spacegroup.create(spaceCell);
  39. return { assemblies: [], spacegroup, isNonStandardCrystalFrame: false };
  40. }
  41. }
  42. function checkNonStandardCrystalFrame(atom_sites: Table<mmCIF_Schema['atom_sites']>, spacegroup: Spacegroup) {
  43. if (atom_sites._rowCount === 0) return false;
  44. // TODO: parse atom_sites transform and check if it corresponds to the toFractional matrix
  45. return false;
  46. }
  47. function getSpacegroupNameOrNumber(symmetry: Table<mmCIF_Schema['symmetry']>) {
  48. const groupNumber = symmetry['Int_Tables_number'].value(0);
  49. const groupName = symmetry['space_group_name_H-M'].value(0);
  50. if (!symmetry['Int_Tables_number'].isDefined) return groupName;
  51. if (!symmetry['space_group_name_H-M'].isDefined) return groupNumber;
  52. return groupName;
  53. }
  54. function getSpacegroup(symmetry: Table<mmCIF_Schema['symmetry']>, cell: Table<mmCIF_Schema['cell']>): Spacegroup {
  55. if (symmetry._rowCount === 0 || cell._rowCount === 0) return Spacegroup.ZeroP1;
  56. const nameOrNumber = getSpacegroupNameOrNumber(symmetry);
  57. const spaceCell = SpacegroupCell.create(nameOrNumber,
  58. Vec3.create(cell.length_a.value(0), cell.length_b.value(0), cell.length_c.value(0)),
  59. Vec3.scale(Vec3.zero(), Vec3.create(cell.angle_alpha.value(0), cell.angle_beta.value(0), cell.angle_gamma.value(0)), Math.PI / 180));
  60. return Spacegroup.create(spaceCell);
  61. }
  62. function getNcsOperators(struct_ncs_oper: Table<mmCIF_Schema['struct_ncs_oper']>) {
  63. if (struct_ncs_oper._rowCount === 0) return void 0;
  64. const { id, matrix, vector } = struct_ncs_oper;
  65. const matrixSpace = mmCIF_Schema.struct_ncs_oper.matrix.space, vectorSpace = mmCIF_Schema.struct_ncs_oper.vector.space;
  66. const opers: SymmetryOperator[] = [];
  67. for (let i = 0; i < struct_ncs_oper._rowCount; i++) {
  68. const m = Tensor.toMat3(Mat3(), matrixSpace, matrix.value(i));
  69. const v = Tensor.toVec3(Vec3(), vectorSpace, vector.value(i));
  70. if (!SymmetryOperator.checkIfRotationAndTranslation(m, v)) continue;
  71. // ignore non-identity 'given' NCS operators
  72. if (struct_ncs_oper.code.value(i) === 'given' && !Mat3.isIdentity(m) && !Vec3.isZero(v)) continue;
  73. const ncsId = id.value(i);
  74. opers[opers.length] = SymmetryOperator.ofRotationAndOffset(`ncs_${ncsId}`, m, v, ncsId);
  75. }
  76. return opers;
  77. }