@@ -411,6 +411,239 @@ TEST(Dataset, isel) {
411411 << " Inline range should end at 5" ;
412412}
413413
414+ TEST (Dataset, iselWithStride) {
415+ // Tests the integrity of data that is written with a strided slice.
416+ std::string iselPath = " zarrs/acceptance" ;
417+ { // Scoping the dataset creation to ensure the variables are cleaned up
418+ // before the testing.
419+ auto json_vars = GetToyExample ();
420+ auto dataset = mdio::Dataset::from_json (json_vars, iselPath,
421+ mdio::constants::kCreateClean );
422+ ASSERT_TRUE (dataset.status ().ok ()) << dataset.status ();
423+ auto ds = dataset.value ();
424+
425+ mdio::RangeDescriptor<mdio::Index> desc1 = {" inline" , 0 , 256 , 2 };
426+ auto sliceRes = ds.isel (desc1);
427+ ASSERT_TRUE (sliceRes.status ().ok ()) << sliceRes.status ();
428+ ds = sliceRes.value ();
429+
430+ auto ilVarRes = ds.variables .get <mdio::dtypes::uint32_t >(" inline" );
431+ ASSERT_TRUE (ilVarRes.status ().ok ()) << ilVarRes.status ();
432+ auto ilVar = ilVarRes.value ();
433+
434+ auto ilDataRes = mdio::from_variable<mdio::dtypes::uint32_t >(ilVar);
435+ ASSERT_TRUE (ilDataRes.status ().ok ()) << ilDataRes.status ();
436+ auto ilData = ilDataRes.value ();
437+
438+ auto ilAccessor = ilData.get_data_accessor ().data ();
439+ for (uint32_t i = 0 ; i < 128 ; i++) {
440+ ilAccessor[i] = i * 2 ;
441+ }
442+
443+ auto ilFut = ilVar.Write (ilData);
444+
445+ ASSERT_TRUE (ilFut.status ().ok ()) << ilFut.status ();
446+
447+ // --- Begin new QC data generation for the "image" variable (float32) ---
448+ auto imageVarRes = ds.variables .get <mdio::dtypes::float32_t >(" image" );
449+ ASSERT_TRUE (imageVarRes.status ().ok ()) << imageVarRes.status ();
450+ auto imageVar = imageVarRes.value ();
451+
452+ auto imageDataRes = mdio::from_variable<mdio::dtypes::float32_t >(imageVar);
453+ ASSERT_TRUE (imageDataRes.status ().ok ()) << imageDataRes.status ();
454+ auto imageData = imageDataRes.value ();
455+
456+ auto imageAccessor = imageData.get_data_accessor ().data ();
457+ for (uint32_t i = 0 ; i < 128 ; i++) {
458+ for (uint32_t j = 0 ; j < 512 ; j++) {
459+ for (uint32_t k = 0 ; k < 384 ; k++) {
460+ imageAccessor[i * (512 * 384 ) + j * 384 + k] =
461+ static_cast <float >(i * 2 ) + j * 0 .1f + k * 0 .01f ;
462+ }
463+ }
464+ }
465+
466+ auto imageWriteFut = imageVar.Write (imageData);
467+ ASSERT_TRUE (imageWriteFut.status ().ok ()) << imageWriteFut.status ();
468+ } // end of scoping the dataset creation to ensure the variables are cleaned
469+ // up before the testing.
470+
471+ auto reopenedDsFut = mdio::Dataset::Open (iselPath, mdio::constants::kOpen );
472+ ASSERT_TRUE (reopenedDsFut.status ().ok ()) << reopenedDsFut.status ();
473+ auto reopenedDs = reopenedDsFut.value ();
474+
475+ auto inlineVarRes =
476+ reopenedDs.variables .get <mdio::dtypes::uint32_t >(" inline" );
477+ ASSERT_TRUE (inlineVarRes.status ().ok ()) << inlineVarRes.status ();
478+ auto inlineVar = inlineVarRes.value ();
479+
480+ auto inlineDataFut = inlineVar.Read ();
481+ ASSERT_TRUE (inlineDataFut.status ().ok ()) << inlineDataFut.status ();
482+ auto inlineData = inlineDataFut.value ();
483+ auto inlineAccessor = inlineData.get_data_accessor ().data ();
484+ for (uint32_t i = 0 ; i < 256 ; i++) {
485+ if (i % 2 == 0 ) {
486+ ASSERT_EQ (inlineAccessor[i], i) << " Expected inline value to be " << i
487+ << " but got " << inlineAccessor[i];
488+ } else {
489+ ASSERT_EQ (inlineAccessor[i], 0 )
490+ << " Expected inline value to be 0 but got " << inlineAccessor[i];
491+ }
492+ }
493+
494+ auto imageVarResReopen =
495+ reopenedDs.variables .get <mdio::dtypes::float32_t >(" image" );
496+ ASSERT_TRUE (imageVarResReopen.status ().ok ()) << imageVarResReopen.status ();
497+ auto imageVarReopen = imageVarResReopen.value ();
498+
499+ auto imageDataFut = imageVarReopen.Read ();
500+ ASSERT_TRUE (imageDataFut.status ().ok ()) << imageDataFut.status ();
501+ auto imageDataFull = imageDataFut.value ();
502+ auto imageAccessorFull = imageDataFull.get_data_accessor ().data ();
503+
504+ // Instead of checking all 256x512x384 elements (which can be very time
505+ // consuming), we check a few sample indices. For full "image" variable, for
506+ // every full inline index i: if (i % 2 == 0): the expected value is i +
507+ // j*0.1f + k*0.01f, otherwise NaN.
508+ std::vector<uint32_t > sample_i = {0 , 1 , 2 ,
509+ 255 }; // mix of even and odd indices
510+ std::vector<uint32_t > sample_j = {0 , 256 , 511 };
511+ std::vector<uint32_t > sample_k = {0 , 100 , 383 };
512+
513+ for (auto i : sample_i) {
514+ for (auto j : sample_j) {
515+ for (auto k : sample_k) {
516+ size_t index = i * (512 * 384 ) + j * 384 + k;
517+ float actual = imageAccessorFull[index];
518+
519+ if (i % 2 == 0 ) {
520+ // For even indices, we expect a specific value
521+ float expected = static_cast <float >(i) + j * 0 .1f + k * 0 .01f ;
522+ ASSERT_FLOAT_EQ (actual, expected)
523+ << " QC mismatch in image variable at (" << i << " , " << j << " , "
524+ << k << " )" ;
525+ } else {
526+ // For odd indices, we expect NaN
527+ ASSERT_TRUE (std::isnan (actual))
528+ << " Expected NaN at (" << i << " , " << j << " , " << k
529+ << " ) but got " << actual;
530+ }
531+ }
532+ }
533+ }
534+ // --- End new QC check for the "image" variable ---
535+ }
536+
537+ TEST (Dataset, iselWithStrideAndExistingData) {
538+ std::string testPath = " zarrs/slice_scale_test" ;
539+ float scaleFactor = 2 .5f ;
540+
541+ // --- Step 1: Initialize the entire image variable with QC values and Write it ---
542+ {
543+ // Create a new dataset
544+ auto json_vars = GetToyExample ();
545+ auto dataset = mdio::Dataset::from_json (json_vars, testPath, mdio::constants::kCreateClean );
546+ ASSERT_TRUE (dataset.status ().ok ()) << dataset.status ();
547+ auto ds = dataset.value ();
548+
549+ // Get the "image" variable (expected to be float32_t type)
550+ auto imageVarRes = ds.variables .get <mdio::dtypes::float32_t >(" image" );
551+ ASSERT_TRUE (imageVarRes.status ().ok ()) << imageVarRes.status ();
552+ auto imageVar = imageVarRes.value ();
553+
554+ auto imageDataRes = mdio::from_variable<mdio::dtypes::float32_t >(imageVar);
555+ ASSERT_TRUE (imageDataRes.status ().ok ()) << imageDataRes.status ();
556+ auto imageData = imageDataRes.value ();
557+ auto imageAccessor = imageData.get_data_accessor ().data ();
558+
559+ // Initialize the entire "image" variable with QC values.
560+ // For this test, we assume dimensions 256 x 512 x 384.
561+ for (uint32_t i = 0 ; i < 256 ; i++) {
562+ for (uint32_t j = 0 ; j < 512 ; j++) {
563+ for (uint32_t k = 0 ; k < 384 ; k++) {
564+ imageAccessor[i * (512 * 384 ) + j * 384 + k] =
565+ static_cast <float >(i) + j * 0 .1f + k * 0 .01f ;
566+ }
567+ }
568+ }
569+
570+ auto writeFut = imageVar.Write (imageData);
571+ ASSERT_TRUE (writeFut.status ().ok ()) << writeFut.status ();
572+ } // End of Step 1
573+
574+ // --- Step 2: Slice with stride of 2 and scale the values of the "image" variable ---
575+ {
576+ // Re-open the dataset for modifications.
577+ auto reopenedDsFut = mdio::Dataset::Open (testPath, mdio::constants::kOpen );
578+ ASSERT_TRUE (reopenedDsFut.status ().ok ()) << reopenedDsFut.status ();
579+ auto ds = reopenedDsFut.value ();
580+
581+ // Slice the dataset along the "inline" dimension using a stride of 2.
582+ mdio::RangeDescriptor<mdio::Index> desc = {" inline" , 0 , 256 , 2 };
583+ auto sliceRes = ds.isel (desc);
584+ ASSERT_TRUE (sliceRes.status ().ok ()) << sliceRes.status ();
585+ auto ds_slice = sliceRes.value ();
586+
587+ // Get the "image" variable from the sliced dataset.
588+ auto imageVarRes = ds_slice.variables .get <mdio::dtypes::float32_t >(" image" );
589+ ASSERT_TRUE (imageVarRes.status ().ok ()) << imageVarRes.status ();
590+ auto imageVar = imageVarRes.value ();
591+
592+ auto imageDataFut = imageVar.Read ();
593+ ASSERT_TRUE (imageDataFut.status ().ok ()) << imageDataFut.status ();
594+ auto imageData = imageDataFut.value ();
595+ auto imageAccessor = imageData.get_data_accessor ().data ();
596+
597+ // The sliced "image" now has dimensions 128 x 512 x 384 because we selected every 2nd index.
598+ // Scale each element in the slice by 'scaleFactor'
599+ for (uint32_t ii = 0 ; ii < 128 ; ii++) { // 'ii' corresponds to original index i = ii * 2.
600+ for (uint32_t j = 0 ; j < 512 ; j++) {
601+ for (uint32_t k = 0 ; k < 384 ; k++) {
602+ size_t index = ii * (512 * 384 ) + j * 384 + k;
603+ imageAccessor[index] *= scaleFactor;
604+ }
605+ }
606+ }
607+ // Write the updated (scaled) data back to the dataset.
608+ auto writeFut = imageVar.Write (imageData);
609+ ASSERT_TRUE (writeFut.status ().ok ()) << writeFut.status ();
610+ } // End of Step 2
611+
612+ // --- Step 3: Read the entire image variable and validate QC values ---
613+ {
614+ // Re-open the dataset for the final validation.
615+ auto reopenedDsFut = mdio::Dataset::Open (testPath, mdio::constants::kOpen );
616+ ASSERT_TRUE (reopenedDsFut.status ().ok ()) << reopenedDsFut.status ();
617+ auto ds = reopenedDsFut.value ();
618+
619+ auto imageVarRes = ds.variables .get <mdio::dtypes::float32_t >(" image" );
620+ ASSERT_TRUE (imageVarRes.status ().ok ()) << imageVarRes.status ();
621+ auto imageVar = imageVarRes.value ();
622+
623+ auto imageReadFut = imageVar.Read ();
624+ ASSERT_TRUE (imageReadFut.status ().ok ()) << imageReadFut.status ();
625+ auto imageData = imageReadFut.value ();
626+ auto imageAccessor = imageData.get_data_accessor ().data ();
627+
628+ // Validate the values over the entire "image" variable.
629+ // For even inline indices (i % 2 == 0) we expect the initial QC value scaled by 'scaleFactor'.
630+ // For odd inline indices, the original QC values should remain.
631+ for (uint32_t i = 0 ; i < 256 ; i++) {
632+ for (uint32_t j = 0 ; j < 512 ; j++) {
633+ for (uint32_t k = 0 ; k < 384 ; k++) {
634+ size_t index = i * (512 * 384 ) + j * 384 + k;
635+ float baseValue = static_cast <float >(i) + j * 0 .1f + k * 0 .01f ;
636+ float expected = (i % 2 == 0 ) ? baseValue * scaleFactor : baseValue;
637+ auto val = imageAccessor[index];
638+ ASSERT_FLOAT_EQ (val, expected)
639+ << " Mismatch at (" << i << " , " << j << " , " << k
640+ << " ): expected " << expected << " , but got " << val;
641+ }
642+ }
643+ }
644+ } // End of Step 3
645+ }
646+
414647TEST (Dataset, selValue) {
415648 std::string path = " zarrs/selTester.mdio" ;
416649 auto dsRes = makePopulated (path);
0 commit comments