@gmod/hic 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +91 -0
  3. package/dist/binWindow.d.ts +24 -0
  4. package/dist/binWindow.js +32 -0
  5. package/dist/binWindow.js.map +1 -0
  6. package/dist/binary.d.ts +15 -0
  7. package/dist/binary.js +67 -0
  8. package/dist/binary.js.map +1 -0
  9. package/dist/bufferedFile.d.ts +13 -0
  10. package/dist/bufferedFile.js +78 -0
  11. package/dist/bufferedFile.js.map +1 -0
  12. package/dist/contactRecords.d.ts +25 -0
  13. package/dist/contactRecords.js +3 -0
  14. package/dist/contactRecords.js.map +1 -0
  15. package/dist/hicFile.d.ts +94 -0
  16. package/dist/hicFile.js +769 -0
  17. package/dist/hicFile.js.map +1 -0
  18. package/dist/index.d.ts +5 -0
  19. package/dist/index.js +9 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/lru.d.ts +29 -0
  22. package/dist/lru.js +55 -0
  23. package/dist/lru.js.map +1 -0
  24. package/dist/matrix.d.ts +9 -0
  25. package/dist/matrix.js +41 -0
  26. package/dist/matrix.js.map +1 -0
  27. package/dist/matrixZoomData.d.ts +14 -0
  28. package/dist/matrixZoomData.js +96 -0
  29. package/dist/matrixZoomData.js.map +1 -0
  30. package/dist/normalizationVector.d.ts +10 -0
  31. package/dist/normalizationVector.js +51 -0
  32. package/dist/normalizationVector.js.map +1 -0
  33. package/dist/package.json +1 -0
  34. package/dist/reader.d.ts +3 -0
  35. package/dist/reader.js +12 -0
  36. package/dist/reader.js.map +1 -0
  37. package/dist/types.d.ts +35 -0
  38. package/dist/types.js +3 -0
  39. package/dist/types.js.map +1 -0
  40. package/esm/binWindow.d.ts +24 -0
  41. package/esm/binWindow.js +29 -0
  42. package/esm/binWindow.js.map +1 -0
  43. package/esm/binary.d.ts +15 -0
  44. package/esm/binary.js +64 -0
  45. package/esm/binary.js.map +1 -0
  46. package/esm/bufferedFile.d.ts +13 -0
  47. package/esm/bufferedFile.js +75 -0
  48. package/esm/bufferedFile.js.map +1 -0
  49. package/esm/contactRecords.d.ts +25 -0
  50. package/esm/contactRecords.js +2 -0
  51. package/esm/contactRecords.js.map +1 -0
  52. package/esm/hicFile.d.ts +94 -0
  53. package/esm/hicFile.js +762 -0
  54. package/esm/hicFile.js.map +1 -0
  55. package/esm/index.d.ts +5 -0
  56. package/esm/index.js +3 -0
  57. package/esm/index.js.map +1 -0
  58. package/esm/lru.d.ts +29 -0
  59. package/esm/lru.js +52 -0
  60. package/esm/lru.js.map +1 -0
  61. package/esm/matrix.d.ts +9 -0
  62. package/esm/matrix.js +35 -0
  63. package/esm/matrix.js.map +1 -0
  64. package/esm/matrixZoomData.d.ts +14 -0
  65. package/esm/matrixZoomData.js +93 -0
  66. package/esm/matrixZoomData.js.map +1 -0
  67. package/esm/normalizationVector.d.ts +10 -0
  68. package/esm/normalizationVector.js +45 -0
  69. package/esm/normalizationVector.js.map +1 -0
  70. package/esm/reader.d.ts +3 -0
  71. package/esm/reader.js +9 -0
  72. package/esm/reader.js.map +1 -0
  73. package/esm/types.d.ts +35 -0
  74. package/esm/types.js +2 -0
  75. package/esm/types.js.map +1 -0
  76. package/package.json +73 -0
  77. package/src/binWindow.ts +30 -0
  78. package/src/binary.ts +72 -0
  79. package/src/bufferedFile.ts +74 -0
  80. package/src/contactRecords.ts +25 -0
  81. package/src/hicFile.ts +943 -0
  82. package/src/index.ts +12 -0
  83. package/src/lru.ts +77 -0
  84. package/src/matrix.ts +43 -0
  85. package/src/matrixZoomData.ts +133 -0
  86. package/src/normalizationVector.ts +58 -0
  87. package/src/reader.ts +11 -0
  88. package/src/types.ts +40 -0
@@ -0,0 +1,74 @@
1
+ import type { Reader } from './types.ts'
2
+
3
+ function concatBuffers(buffer1: ArrayBuffer, buffer2: ArrayBuffer) {
4
+ const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength)
5
+ tmp.set(new Uint8Array(buffer1), 0)
6
+ tmp.set(new Uint8Array(buffer2), buffer1.byteLength)
7
+ return tmp.buffer
8
+ }
9
+
10
+ export default class BufferedFile {
11
+ private file: Reader
12
+ private size: number
13
+ private bufferStart = 0
14
+ private bufferLength = 0
15
+ private buffer: ArrayBuffer | undefined
16
+
17
+ constructor(args: { file: Reader; size?: number }) {
18
+ this.file = args.file
19
+ this.size = args.size ?? 64000
20
+ }
21
+
22
+ async read(position: number, length: number): Promise<ArrayBuffer> {
23
+ const start = position
24
+ const end = position + length
25
+ const bufferStart = this.bufferStart
26
+ const bufferEnd = this.bufferStart + this.bufferLength
27
+ const buf = this.buffer
28
+
29
+ let result: ArrayBuffer
30
+ if (length > this.size) {
31
+ // Request larger than max buffer size, pass through to underlying file
32
+ this.buffer = undefined
33
+ this.bufferStart = 0
34
+ this.bufferLength = 0
35
+ result = await this.file.read(position, length)
36
+ } else if (buf && start >= bufferStart && end <= bufferEnd) {
37
+ // Request within buffer bounds
38
+ const sliceStart = start - bufferStart
39
+ result = buf.slice(sliceStart, sliceStart + length)
40
+ } else if (buf && start < bufferStart && end > bufferStart) {
41
+ // Overlap left (unexpected in straw); we don't adjust the buffer
42
+ const l1 = bufferStart - start
43
+ const a1 = await this.file.read(position, l1)
44
+ const l2 = length - l1
45
+ if (l2 > 0) {
46
+ result = concatBuffers(a1, buf.slice(0, l2))
47
+ } else {
48
+ result = a1
49
+ }
50
+ } else if (buf && start < bufferEnd && end > bufferEnd) {
51
+ // Overlap right
52
+ const l1 = bufferEnd - start
53
+ const a1 = buf.slice(this.bufferLength - l1, this.bufferLength)
54
+ const l2 = length - l1
55
+ if (l2 > 0) {
56
+ const next = await this.file.read(bufferEnd, this.size)
57
+ this.buffer = next
58
+ this.bufferStart = bufferEnd
59
+ this.bufferLength = next.byteLength
60
+ result = concatBuffers(a1, next.slice(0, l2))
61
+ } else {
62
+ result = a1
63
+ }
64
+ } else {
65
+ // No overlap with buffer
66
+ const next = await this.file.read(position, this.size)
67
+ this.buffer = next
68
+ this.bufferStart = position
69
+ this.bufferLength = next.byteLength
70
+ result = next.slice(0, length)
71
+ }
72
+ return result
73
+ }
74
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * A run of contact records, held struct-of-arrays.
3
+ *
4
+ * hic-straw models a contact as an object, and the whole read path inherits
5
+ * that shape: a block holds `ContactRecord[]` and the window filter rebuilds
6
+ * the array. A renderer then has to unpack that into typed arrays anyway, so a
7
+ * contact was allocated several times over on its way to a vertex buffer — and
8
+ * a matrix is routinely millions of contacts.
9
+ *
10
+ * The per-contact allocation is the obvious cost, but the block cache is the
11
+ * expensive one: cached blocks are long-lived, so as objects they left millions
12
+ * of live pointers for every GC to trace for the rest of the session. Twelve
13
+ * bytes a contact here against ~50 for an object, and nothing for the collector
14
+ * to walk.
15
+ *
16
+ * The three arrays are always exactly the same length — `bin1.length` is the
17
+ * record count. Counts are float32 because that is what the file stores
18
+ * (`getFloat`/`getShort`) and what a GPU renderer takes, so carrying them as
19
+ * doubles only ever widened a value on its way back down to float32.
20
+ */
21
+ export interface ContactRecords {
22
+ bin1: Int32Array
23
+ bin2: Int32Array
24
+ counts: Float32Array
25
+ }