model.ts 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /**
  2. * Copyright (c) 2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import { Column, Table } from '../../mol-data/db';
  7. import { OrderedSet } from '../../mol-data/int';
  8. import { Vec3 } from '../../mol-math/linear-algebra';
  9. import { createModels } from '../../mol-model-formats/structure/basic/parser';
  10. import { BasicSchema, createBasic } from '../../mol-model-formats/structure/basic/schema';
  11. import { EntityBuilder } from '../../mol-model-formats/structure/common/entity';
  12. import { Loci } from '../../mol-model/loci';
  13. import { Trajectory, Unit } from '../../mol-model/structure';
  14. import { MoleculeType } from '../../mol-model/structure/model/types';
  15. import { LociLabelProvider } from '../../mol-plugin-state/manager/loci-label';
  16. import { MolScriptBuilder as MS } from '../../mol-script/language/builder';
  17. import { CustomPropSymbol } from '../../mol-script/language/symbol';
  18. import { Type } from '../../mol-script/language/type';
  19. import { QuerySymbolRuntime } from '../../mol-script/runtime/query/base';
  20. import { RuntimeContext, Task } from '../../mol-task';
  21. import { objectForEach } from '../../mol-util/object';
  22. import { G3dDataBlock } from './data';
  23. import { FormatPropertyProvider } from '../../mol-model-formats/structure/common/property';
  24. interface NormalizedData {
  25. entity_id: string[],
  26. chromosome: string[],
  27. seq_id_begin: Int32Array,
  28. seq_id_end: Int32Array,
  29. start: Int32Array,
  30. x: Float32Array,
  31. y: Float32Array,
  32. z: Float32Array,
  33. r: Float32Array,
  34. haplotype: string[]
  35. }
  36. function getColumns(block: G3dDataBlock) {
  37. const { data } = block;
  38. let size = 0;
  39. objectForEach(data, h => objectForEach(h, g => size += g.start.length));
  40. const normalized: NormalizedData = {
  41. entity_id: new Array(size),
  42. chromosome: new Array(size),
  43. seq_id_begin: new Int32Array(size),
  44. seq_id_end: new Int32Array(size),
  45. start: new Int32Array(size),
  46. x: new Float32Array(size),
  47. y: new Float32Array(size),
  48. z: new Float32Array(size),
  49. r: new Float32Array(size),
  50. haplotype: new Array(size)
  51. };
  52. const p = [Vec3(), Vec3(), Vec3()];
  53. let o = 0;
  54. objectForEach(data, (hs, h) => {
  55. objectForEach(hs, (chs, ch) => {
  56. const entity_id = `${ch}-${h}`;
  57. const l = chs.start.length;
  58. if (l === 0) return;
  59. let x = chs.x[0];
  60. let y = chs.y[0];
  61. let z = chs.z[0];
  62. Vec3.set(p[0], x, y, z);
  63. Vec3.set(p[2], x, y, z);
  64. for (let i = 0; i < l; i++) {
  65. normalized.entity_id[o] = entity_id;
  66. normalized.chromosome[o] = ch;
  67. normalized.start[o] = chs.start[i];
  68. normalized.seq_id_begin[o] = o;
  69. normalized.seq_id_end[o] = o;
  70. x = chs.x[i];
  71. y = chs.y[i];
  72. z = chs.z[i];
  73. Vec3.set(p[1], x, y, z);
  74. if (i + 1 < l) Vec3.set(p[2], chs.x[i + 1], chs.y[i + 1], chs.z[i + 1]);
  75. else Vec3.set(p[2], x, y, z);
  76. normalized.x[o] = x;
  77. normalized.y[o] = y;
  78. normalized.z[o] = z;
  79. normalized.r[o] = 2 / 3 * Math.min(Vec3.distance(p[0], p[1]), Vec3.distance(p[1], p[2]));
  80. normalized.haplotype[o] = h;
  81. const _p = p[0];
  82. p[0] = p[1];
  83. p[1] = _p;
  84. o++;
  85. }
  86. if (l === 1) {
  87. normalized.r[o - 1] = 1;
  88. }
  89. });
  90. });
  91. return normalized;
  92. }
  93. async function getTraj(ctx: RuntimeContext, data: G3dDataBlock) {
  94. const normalized = getColumns(data);
  95. const rowCount = normalized.seq_id_begin.length;
  96. const entityIds = new Array<string>(rowCount);
  97. const entityBuilder = new EntityBuilder();
  98. const eName = { customName: '' };
  99. for (let i = 0; i < rowCount; ++i) {
  100. const e = normalized.entity_id[i];
  101. eName.customName = e;
  102. const entityId = entityBuilder.getEntityId(e, MoleculeType.DNA, e, eName);
  103. entityIds[i] = entityId;
  104. }
  105. const ihm_sphere_obj_site = Table.ofPartialColumns(BasicSchema.ihm_sphere_obj_site, {
  106. id: Column.range(0, rowCount),
  107. entity_id: Column.ofStringArray(entityIds),
  108. seq_id_begin: Column.ofIntArray(normalized.seq_id_begin),
  109. seq_id_end: Column.ofIntArray(normalized.seq_id_end),
  110. asym_id: Column.ofStringArray(normalized.chromosome),
  111. Cartn_x: Column.ofFloatArray(normalized.x),
  112. Cartn_y: Column.ofFloatArray(normalized.y),
  113. Cartn_z: Column.ofFloatArray(normalized.z),
  114. object_radius: Column.ofFloatArray(normalized.r),
  115. rmsf: Column.ofConst(0, rowCount, Column.Schema.float),
  116. model_id: Column.ofConst(1, rowCount, Column.Schema.int),
  117. }, rowCount);
  118. const basic = createBasic({
  119. entity: entityBuilder.getEntityTable(),
  120. ihm_model_list: Table.ofPartialColumns(BasicSchema.ihm_model_list, {
  121. model_id: Column.ofIntArray([1]),
  122. model_name: Column.ofStringArray(['G3D Model']),
  123. }, 1),
  124. ihm_sphere_obj_site
  125. });
  126. const models = await createModels(basic, { kind: 'g3d', name: 'G3D', data }, ctx);
  127. G3dInfoDataProperty.set(models.representative, {
  128. haplotypes: Object.keys(data.data),
  129. haplotype: normalized.haplotype,
  130. resolution: data.resolution,
  131. start: normalized.start,
  132. chroms: normalized.chromosome,
  133. });
  134. return models;
  135. }
  136. export function trajectoryFromG3D(data: G3dDataBlock): Task<Trajectory> {
  137. return Task.create('Parse G3D', async ctx => {
  138. return getTraj(ctx, data);
  139. });
  140. }
  141. export const G3dSymbols = {
  142. haplotype: QuerySymbolRuntime.Dynamic(CustomPropSymbol('g3d', 'haplotype', Type.Str),
  143. ctx => {
  144. if (Unit.isAtomic(ctx.element.unit)) return '';
  145. const info = (G3dInfoDataProperty as any).get(ctx.element.unit.model);
  146. if (!info) return '';
  147. const seqId = ctx.element.unit.model.coarseHierarchy.spheres.seq_id_begin.value(ctx.element.element);
  148. return info.haplotype[seqId] || '';
  149. }
  150. ),
  151. chromosome: QuerySymbolRuntime.Dynamic(CustomPropSymbol('g3d', 'chromosome', Type.Str),
  152. ctx => {
  153. if (Unit.isAtomic(ctx.element.unit)) return '';
  154. const { asym_id } = ctx.element.unit.model.coarseHierarchy.spheres;
  155. return asym_id.value(ctx.element.element) || '';
  156. }
  157. ),
  158. region: QuerySymbolRuntime.Dynamic(CustomPropSymbol('g3d', 'region', Type.Num),
  159. ctx => {
  160. if (Unit.isAtomic(ctx.element.unit)) return '';
  161. const info = (G3dInfoDataProperty as any).get(ctx.element.unit.model);
  162. if (!info) return 0;
  163. const seqId = ctx.element.unit.model.coarseHierarchy.spheres.seq_id_begin.value(ctx.element.element);
  164. return info.start[seqId] || 0;
  165. }
  166. )
  167. };
  168. export const G3dInfoDataProperty = FormatPropertyProvider.create<G3dInfoData>({ name: 'g3d_info' });
  169. export function g3dHaplotypeQuery(haplotype: string) {
  170. return MS.struct.generator.atomGroups({
  171. 'chain-test': MS.core.rel.eq([G3dSymbols.haplotype.symbol(), haplotype]),
  172. });
  173. }
  174. export function g3dChromosomeQuery(chr: string) {
  175. return MS.struct.generator.atomGroups({
  176. 'chain-test': MS.core.logic.and([
  177. MS.core.rel.eq([MS.ammp('objectPrimitive'), 'sphere']),
  178. MS.core.rel.eq([G3dSymbols.chromosome.symbol(), chr])
  179. ])
  180. });
  181. }
  182. export function g3dRegionQuery(chr: string, start: number, end: number) {
  183. return MS.struct.generator.atomGroups({
  184. 'chain-test': MS.core.logic.and([
  185. MS.core.rel.eq([MS.ammp('objectPrimitive'), 'sphere']),
  186. MS.core.rel.eq([G3dSymbols.chromosome.symbol(), chr])
  187. ]),
  188. 'residue-test': MS.core.rel.inRange([G3dSymbols.region.symbol(), start, end])
  189. });
  190. }
  191. export interface G3dInfoData {
  192. haplotypes: string[],
  193. haplotype: string[],
  194. start: Int32Array,
  195. resolution: number,
  196. chroms: string[]
  197. };
  198. export const G3dLabelProvider: LociLabelProvider = {
  199. label: (e: Loci): string | undefined => {
  200. if (e.kind !== 'element-loci' || Loci.isEmpty(e)) return;
  201. const first = e.elements[0];
  202. if (e.elements.length !== 1 || Unit.isAtomic(first.unit)) return;
  203. const info = G3dInfoDataProperty.get(first.unit.model);
  204. if (!info) return;
  205. const eI = first.unit.elements[OrderedSet.getAt(first.indices, 0)];
  206. const seqId = first.unit.model.coarseHierarchy.spheres.seq_id_begin.value(eI);
  207. return `<b>Start:</b> ${info.start[seqId]} <small>| resolution ${info.resolution}<small>`;
  208. }
  209. };