encode.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * Taken/adapted from DensityServer (https://github.com/dsehnal/DensityServer)
  5. *
  6. * @author David Sehnal <david.sehnal@gmail.com>
  7. */
  8. import { CifWriter } from '../../../../mol-io/writer/cif';
  9. import * as Data from './data-model';
  10. import * as Coords from '../algebra/coordinate';
  11. import { VOLUME_SERVER_VERSION as VERSION } from '../version';
  12. import * as DataFormat from '../../common/data-format';
  13. import { Column } from '../../../../mol-data/db';
  14. import { ArrayEncoding, ArrayEncoder } from '../../../../mol-io/common/binary-cif';
  15. import { TypedArrayValueType, TypedArrayValueArray } from '../../../../mol-io/common/typed-array';
  16. export function encode(query: Data.QueryContext, output: Data.QueryOutputStream) {
  17. const w = CifWriter.createEncoder({ binary: query.params.asBinary, encoderName: `VolumeServer ${VERSION}` });
  18. write(w, query);
  19. w.encode();
  20. w.writeTo(output);
  21. }
  22. interface ResultContext {
  23. query: Data.QueryContext.Data,
  24. channelIndex: number
  25. }
  26. function string<T>(name: string, str: (data: T) => string, isSpecified?: (data: T) => boolean): CifWriter.Field<number, T> {
  27. if (isSpecified) {
  28. return CifWriter.Field.str(name, (i, d) => str(d), { valueKind: (i, d) => isSpecified(d) ? Column.ValueKinds.Present : Column.ValueKinds.NotPresent });
  29. }
  30. return CifWriter.Field.str(name, (i, d) => str(d));
  31. }
  32. function int32<T>(name: string, value: (data: T) => number): CifWriter.Field<number, T> {
  33. return CifWriter.Field.int(name, (i, d) => value(d));
  34. }
  35. function float64<T>(name: string, value: (data: T) => number, digitCount: number = 6): CifWriter.Field<number, T> {
  36. return CifWriter.Field.float(name, (i, d) => value(d), { digitCount: digitCount, typedArray: Float64Array });
  37. }
  38. interface _vd3d_Ctx {
  39. header: DataFormat.Header,
  40. channelIndex: number,
  41. grid: Coords.GridDomain<'Query'>,
  42. sampleRate: number,
  43. globalValuesInfo: DataFormat.ValuesInfo,
  44. sampledValuesInfo: DataFormat.ValuesInfo,
  45. }
  46. const _volume_data_3d_info_fields = [
  47. string<_vd3d_Ctx>('name', ctx => ctx.header.channels[ctx.channelIndex]),
  48. int32<_vd3d_Ctx>('axis_order[0]', ctx => ctx.header.axisOrder[0]),
  49. int32<_vd3d_Ctx>('axis_order[1]', ctx => ctx.header.axisOrder[1]),
  50. int32<_vd3d_Ctx>('axis_order[2]', ctx => ctx.header.axisOrder[2]),
  51. float64<_vd3d_Ctx>('origin[0]', ctx => ctx.grid.origin[0]),
  52. float64<_vd3d_Ctx>('origin[1]', ctx => ctx.grid.origin[1]),
  53. float64<_vd3d_Ctx>('origin[2]', ctx => ctx.grid.origin[2]),
  54. float64<_vd3d_Ctx>('dimensions[0]', ctx => ctx.grid.dimensions[0]),
  55. float64<_vd3d_Ctx>('dimensions[1]', ctx => ctx.grid.dimensions[1]),
  56. float64<_vd3d_Ctx>('dimensions[2]', ctx => ctx.grid.dimensions[2]),
  57. int32<_vd3d_Ctx>('sample_rate', ctx => ctx.sampleRate),
  58. int32<_vd3d_Ctx>('sample_count[0]', ctx => ctx.grid.sampleCount[0]),
  59. int32<_vd3d_Ctx>('sample_count[1]', ctx => ctx.grid.sampleCount[1]),
  60. int32<_vd3d_Ctx>('sample_count[2]', ctx => ctx.grid.sampleCount[2]),
  61. int32<_vd3d_Ctx>('spacegroup_number', ctx => ctx.header.spacegroup.number),
  62. float64<_vd3d_Ctx>('spacegroup_cell_size[0]', ctx => ctx.header.spacegroup.size[0], 3),
  63. float64<_vd3d_Ctx>('spacegroup_cell_size[1]', ctx => ctx.header.spacegroup.size[1], 3),
  64. float64<_vd3d_Ctx>('spacegroup_cell_size[2]', ctx => ctx.header.spacegroup.size[2], 3),
  65. float64<_vd3d_Ctx>('spacegroup_cell_angles[0]', ctx => ctx.header.spacegroup.angles[0], 3),
  66. float64<_vd3d_Ctx>('spacegroup_cell_angles[1]', ctx => ctx.header.spacegroup.angles[1], 3),
  67. float64<_vd3d_Ctx>('spacegroup_cell_angles[2]', ctx => ctx.header.spacegroup.angles[2], 3),
  68. float64<_vd3d_Ctx>('mean_source', ctx => ctx.globalValuesInfo.mean),
  69. float64<_vd3d_Ctx>('mean_sampled', ctx => ctx.sampledValuesInfo.mean),
  70. float64<_vd3d_Ctx>('sigma_source', ctx => ctx.globalValuesInfo.sigma),
  71. float64<_vd3d_Ctx>('sigma_sampled', ctx => ctx.sampledValuesInfo.sigma),
  72. float64<_vd3d_Ctx>('min_source', ctx => ctx.globalValuesInfo.min),
  73. float64<_vd3d_Ctx>('min_sampled', ctx => ctx.sampledValuesInfo.min),
  74. float64<_vd3d_Ctx>('max_source', ctx => ctx.globalValuesInfo.max),
  75. float64<_vd3d_Ctx>('max_sampled', ctx => ctx.sampledValuesInfo.max)
  76. ];
  77. const _volume_data_3d_info: CifWriter.Category<ResultContext> = {
  78. name: 'volume_data_3d_info',
  79. instance(result) {
  80. const ctx: _vd3d_Ctx = {
  81. header: result.query.data.header,
  82. channelIndex: result.channelIndex,
  83. grid: result.query.samplingInfo.gridDomain,
  84. sampleRate: result.query.samplingInfo.sampling.rate,
  85. globalValuesInfo: result.query.data.header.sampling[0].valuesInfo[result.channelIndex],
  86. sampledValuesInfo: result.query.data.header.sampling[result.query.samplingInfo.sampling.index].valuesInfo[result.channelIndex]
  87. };
  88. return { fields: _volume_data_3d_info_fields, source: [{ data: ctx, rowCount: 1 }] };
  89. }
  90. };
  91. function _volume_data_3d_number(i: number, ctx: TypedArrayValueArray): number {
  92. return ctx[i];
  93. }
  94. const _volume_data_3d: CifWriter.Category<ResultContext> = {
  95. name: 'volume_data_3d',
  96. instance(ctx) {
  97. const data = ctx.query.values[ctx.channelIndex];
  98. const E = ArrayEncoding;
  99. let encoder: ArrayEncoder;
  100. let typedArray: any;
  101. if (ctx.query.data.header.valueType === TypedArrayValueType.Float32 || ctx.query.data.header.valueType === TypedArrayValueType.Int16) {
  102. let min: number, max: number;
  103. min = data[0], max = data[0];
  104. for (let i = 0, n = data.length; i < n; i++) {
  105. const v = data[i];
  106. if (v < min) min = v;
  107. else if (v > max) max = v;
  108. }
  109. typedArray = Float32Array;
  110. // encode into 255 steps and store each value in 1 byte.
  111. encoder = E.by(E.intervalQuantizaiton(min, max, 255, Uint8Array)).and(E.byteArray);
  112. } else {
  113. typedArray = Int8Array;
  114. // just encode the bytes
  115. encoder = E.by(E.byteArray);
  116. }
  117. const fields = [CifWriter.Field.float('values', _volume_data_3d_number, { encoder, typedArray, digitCount: 6 })];
  118. return CifWriter.categoryInstance(fields, { data, rowCount: data.length });
  119. }
  120. };
  121. function pickQueryBoxDimension(ctx: Data.QueryContext, e: 'a' | 'b', d: number) {
  122. const box = ctx.params.box;
  123. switch (box.kind) {
  124. case 'Cartesian':
  125. case 'Fractional':
  126. return `${Math.round(1000000 * box[e][d]) / 1000000}`;
  127. default: return '';
  128. }
  129. }
  130. function queryBoxDimension(e: 'a' | 'b', d: number) {
  131. return string<Data.QueryContext>(`query_box_${e}[${d}]`, ctx => pickQueryBoxDimension(ctx, e, d), ctx => ctx.params.box.kind !== 'Cell');
  132. }
  133. const _density_server_result_fields = [
  134. string<Data.QueryContext>('server_version', ctx => VERSION),
  135. string<Data.QueryContext>('datetime_utc', ctx => new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '')),
  136. string<Data.QueryContext>('guid', ctx => ctx.guid),
  137. string<Data.QueryContext>('is_empty', ctx => ctx.kind === 'Empty' || ctx.kind === 'Error' ? 'yes' : 'no'),
  138. string<Data.QueryContext>('has_error', ctx => ctx.kind === 'Error' ? 'yes' : 'no'),
  139. string<Data.QueryContext>('error', ctx => ctx.kind === 'Error' ? ctx.message : '', (ctx) => ctx.kind === 'Error'),
  140. string<Data.QueryContext>('query_source_id', ctx => ctx.params.sourceId),
  141. string<Data.QueryContext>('query_type', ctx => 'box'),
  142. string<Data.QueryContext>('query_box_type', ctx => ctx.params.box.kind.toLowerCase()),
  143. queryBoxDimension('a', 0),
  144. queryBoxDimension('a', 1),
  145. queryBoxDimension('a', 2),
  146. queryBoxDimension('b', 0),
  147. queryBoxDimension('b', 1),
  148. queryBoxDimension('b', 2)
  149. ];
  150. const _density_server_result: CifWriter.Category<Data.QueryContext> = {
  151. name: 'density_server_result',
  152. instance: ctx => CifWriter.categoryInstance(_density_server_result_fields, { data: ctx, rowCount: 1 })
  153. };
  154. function write(encoder: CifWriter.Encoder, query: Data.QueryContext) {
  155. encoder.startDataBlock('SERVER');
  156. encoder.writeCategory(_density_server_result, query);
  157. switch (query.kind) {
  158. case 'Data':
  159. }
  160. if (query.kind === 'Data') {
  161. const header = query.data.header;
  162. for (let i = 0; i < header.channels.length; i++) {
  163. encoder.startDataBlock(header.channels[i]);
  164. const ctx: ResultContext = { query, channelIndex: i };
  165. encoder.writeCategory(_volume_data_3d_info, ctx);
  166. encoder.writeCategory(_volume_data_3d, ctx);
  167. }
  168. }
  169. }