diff --git a/src/components/ui/MainPanel/MetaDataInfo.tsx b/src/components/ui/MainPanel/MetaDataInfo.tsx index a6c52e4f..f93d070a 100644 --- a/src/components/ui/MainPanel/MetaDataInfo.tsx +++ b/src/components/ui/MainPanel/MetaDataInfo.tsx @@ -93,8 +93,37 @@ const MetaDataInfo = ({ meta, metadata, setShowMeta, setOpenVariables, popoverSi const zLength = useMemo(() => meta.shape ? meta.shape[shapeLength-3] : 0, [meta]) const yLength = useMemo(() => meta.shape ? meta.shape[shapeLength-2] : 0, [meta]) const xLength = useMemo(() => meta.shape ? meta.shape[shapeLength-1] : 0, [meta]) - const dataShape = coarsen ? meta.shape.map((val: number, idx: number) => Math.floor(idx === 0 ? val/kernelDepth : val/kernelSize)): meta.shape - const chunkShape = coarsen ? meta.chunks.map((val: number, idx: number) => Math.floor(idx === 0 ? val/kernelDepth : val/kernelSize)): meta.chunks + const { dataShape, chunkShape } = useMemo(() => { + if (coarsen) { + const n = meta.shape.length; + const Coarsen = (val: number, idx:number ) =>{ + if (n <= 2) { + return Math.floor(val / kernelSize); + } + const thirdLast = n - 3; + const secondLast = n - 2; + const last = n - 1; + if (idx === thirdLast) { + return Math.floor(val / kernelDepth); + } + if (idx === secondLast || idx === last) { + return Math.floor(val / kernelSize); + } + return val; + } + const dataShape = meta.shape.map((val: number, idx: number) => { + return Coarsen(val, idx) + }); + const chunkShape = meta.chunks.map((val: number, idx: number) => { + return Coarsen(val, idx) + }); + return { dataShape, chunkShape }; + } + return { + dataShape: meta.shape, + chunkShape: meta.chunks + }; + }, [meta, coarsen, kernelDepth, kernelSize]); // ---- Booleans ---- // const is3D = useMemo(() => meta.shape ? meta.shape.length == 3 : false, [meta]) @@ -235,7 +264,11 @@ const MetaDataInfo = ({ meta, metadata, setShowMeta, setOpenVariables, popoverSi
-
+
= 3 ? 'visible' : 'hidden' + }} + > Temporal Coarsening { diff --git a/src/components/ui/MainPanel/PlayButton.tsx b/src/components/ui/MainPanel/PlayButton.tsx index d76b566b..53d043ca 100644 --- a/src/components/ui/MainPanel/PlayButton.tsx +++ b/src/components/ui/MainPanel/PlayButton.tsx @@ -126,7 +126,8 @@ const PlayInterFace = ({visible, setKeepOpen}:{visible : boolean, setKeepOpen: R let timeSlice = timeArray?.slice(zSlice[0], zSlice[1] ?? undefined) const timeLength = timeArray?.length || 1 let sliceDist = zSlice[1] ? zSlice[1] - zSlice[0] : timeLength - zSlice[0] - if (coarsen) { + + if (coarsen && timeSlice) { timeSlice = coarsenFlatArray(timeSlice, kernel.kernelDepth) sliceDist = Math.floor(sliceDist/kernel.kernelDepth) } diff --git a/src/components/zarr/ZarrGetters.ts b/src/components/zarr/ZarrGetters.ts index ee123720..d7528792 100644 --- a/src/components/zarr/ZarrGetters.ts +++ b/src/components/zarr/ZarrGetters.ts @@ -2,7 +2,7 @@ import { useZarrStore, useCacheStore, useGlobalStore, useErrorStore } from "@/Gl import * as zarr from 'zarrita'; import { CompressArray, DecompressArray, ZarrError, RescaleArray, ToFloat16, copyChunkToArray } from "./ZarrLoaderLRU"; import { GetSize } from "./GetMetadata"; -import { Convolve } from "../computation/webGPU"; +import { Convolve, Convolve2D } from "../computation/webGPU"; import { coarsen3DArray, calculateStrides } from "@/utils/HelperFuncs"; export async function GetZarrDims(variable: string){ @@ -149,52 +149,45 @@ export async function GetZarrArray(){ if (is4D){ chunkShape = chunkShape.slice(1); } + const is2D = outVar.shape.length === 2; - const notChunked = fullShape.every((dim, idx) => dim > chunkShape[idx]); - - // ---- I THINK THIS CODE IS REDUNDANT. BUT NEED TO TEST ON AN UNCHUNCKED ZARR DATASET TO BE SURE ---- // - - // //---- Strategy 1. Download whole array (No time chunks) ----// - // if (notChunked){ - // setStatus("Downloading...") - // const chunk = await fetchWithRetry( - // () => is4D ? zarr.get(outVar, [idx4D, null, null, null]) : zarr.get(outVar), - // `variable ${variable}`, - // setStatus - // ); - // if (!chunk) throw new Error('Unexpected: chunk was not assigned'); // This is redundant but satisfies TypeScript - // if (chunk.data instanceof BigInt64Array || chunk.data instanceof BigUint64Array) { - // throw new Error("BigInt arrays not supported."); - // } - // const shape = is4D ? outVar.shape.slice(1) : outVar.shape; - // const strides = chunk.stride; - // setStrides(strides) // Need strides for the point cloud - - // let [typedArray, scalingFactor] = ToFloat16(chunk.data.map((v: number) => v === fillValue ? NaN : v) as Float32Array, null) - // if (coarsen){ - // typedArray = await Convolve(typedArray, {shape, strides}, "Mean", {kernelSize, kernelDepth}) as Float16Array - // const newShape = shape.map((dim, idx) => Math.ceil(dim / (idx === 0 ? kernelDepth : kernelSize))) - // let newStrides = newShape.slice() - // newStrides = newStrides.map((val, idx) => { - // return newStrides.reduce((a, b, i) => a * (i < idx ? b : 1), 1) - // }) - // console.log(newStrides) - // } - // const cacheChunk = { - // data: compress ? CompressArray(typedArray, 7) : typedArray, - // shape: chunk.shape, - // stride: chunk.stride, - // scaling: scalingFactor, - // compressed: compress - // } - // cache.set(is4D ? `${initStore}_${idx4D}_${variable}` : `${initStore}_${variable}`, cacheChunk) - // setStatus(null) - // return { data: typedArray, shape, dtype: outVar.dtype, scalingFactor }; - // } + // //---- Strategy 1. Download whole array (Chunking Logic doesn't work on 2D atm) ----// + if (is2D){ + setStatus("Downloading...") + const chunk = await fetchWithRetry( + () => zarr.get(outVar), + `variable ${variable}`, + setStatus + ); + if (!chunk) throw new Error('Unexpected: chunk was not assigned'); // This is redundant but satisfies TypeScript + if (chunk.data instanceof BigInt64Array || chunk.data instanceof BigUint64Array) { + throw new Error("BigInt arrays not supported."); + } + const shape = outVar.shape; + const strides = chunk.stride; + setStrides(strides) // Need strides for the point cloud - //---- Strategy 2. Download Chunks ----// - const is2D = outVar.shape.length === 2; - + let [typedArray, scalingFactor] = ToFloat16(chunk.data.map((v: number) => v === fillValue ? NaN : v) as Float32Array, null) + if (coarsen){ + typedArray = await Convolve2D(typedArray, {shape, strides}, "Mean2D", kernelSize) as Float16Array + const newShape = shape.map((dim) => Math.ceil(dim / kernelSize)) + let newStrides = newShape.slice() + newStrides = newStrides.map((_val, idx) => { + return newStrides.reduce((a, b, i) => a * (i < idx ? b : 1), 1) + }) + } + const cacheChunk = { + data: compress ? CompressArray(typedArray, 7) : typedArray, + shape: chunk.shape, + stride: chunk.stride, + scaling: scalingFactor, + compressed: compress + } + cache.set(`${initStore}_${variable}`, cacheChunk) + setStatus(null) + return { data: typedArray, shape, dtype: outVar.dtype, scalingFactor }; + } + // Calculate Indices const zIndexOffset = is4D ? 1 : 0;