diff --git a/model_server/base/accessors.py b/model_server/base/accessors.py
index 3725cb23f9a133748accb8ca7b8333cd6782b6c8..7f1e763d2c7e15340fda7673e56deaa401b7af81 100644
--- a/model_server/base/accessors.py
+++ b/model_server/base/accessors.py
@@ -739,8 +739,8 @@ class PatchStack(InMemoryDataAccessor):
         df = pd.DataFrame([
             {
                 'label': i,
-                'area': (mask.iat_data(i).data > 0).sum(),
-                'intensity_sum': (self.iat(i).data * (mask.iat_data(i).data > 0)).sum()
+                'area': (mask.iat(i).data > 0).sum(),
+                'intensity_sum': (self.iat(i).data * (mask.iat(i).data > 0)).sum()
             } for i in range(0, self.count)
         ])
         df['intensity_mean'] = df['intensity_sum'] / df['area']
diff --git a/model_server/base/roiset.py b/model_server/base/roiset.py
index 9b5a0360e22bd58bec118c10075455fcc647f6b4..f97f12a62cf5d871f59f998945f181bc900f1738 100644
--- a/model_server/base/roiset.py
+++ b/model_server/base/roiset.py
@@ -9,7 +9,7 @@ from uuid import uuid4
 import glasbey
 import numpy as np
 import pandas as pd
-from pydantic import BaseModel
+from pydantic import BaseModel, Field
 from scipy.stats import moment
 from skimage.filters import sobel
 
@@ -79,7 +79,10 @@ class RoiSetExportParams(BaseModel):
     object_classes: bool = False
     labels_overlay: Union[RoiSetLabelsOverlayParams, None] = None
     derived_channels: bool = False
-    make_unique_subdirectory: bool = False
+    write_patches_to_subdirectory: bool = Field(
+        False,
+        description='Write all patches to a subdirectory with prefix as name'
+    )
 
 
 def get_label_ids(acc_seg_mask: GenericImageDataAccessor, allow_3d=False, connect_3d=True) -> InMemoryDataAccessor:
@@ -963,49 +966,56 @@ class RoiSet(object):
 
         for k in params.dict().keys():
             pr = prefix
-            subdir = where / k
-            if params.make_unique_subdirectory:
+            subdir = Path(k)
+            if 'patches' in k and params.write_patches_to_subdirectory:
                 subdir = subdir / pr
             kp = params.dict()[k]
             if kp is None:
                 continue
             if k == 'patches_3d':
                 df_exp = self.export_patches(
-                    subdir, prefix=pr, make_3d=True, **kp
+                    where / subdir, prefix=pr, make_3d=True, **kp
                 )
                 record[k] = [str(Path(k) / fn) for fn in df_exp.patch_path]
             if k == 'annotated_patches_2d':
                 df_exp = self.export_patches(
-                    subdir, prefix=pr, make_3d=False, **kp,
+                    where / subdir, prefix=pr, make_3d=False, **kp,
                 )
                 record[k] = [str(Path(k) / fn) for fn in df_exp.patch_path]
             if k == 'patches_2d':
                 df_exp = self.export_patches(
-                    subdir, prefix=pr, make_3d=False, **kp
+                    where / subdir, prefix=pr, make_3d=False, **kp
                 )
-                self._df = self._df.join(df_exp.patch_path.apply(lambda x: str(Path('patches_2d') / x)))
+                self._df = self._df.join(df_exp.patch_path.apply(lambda x: str(subdir / x)))
                 self._df['patch_id'] = self._df.apply(lambda _: uuid4(), axis=1)
                 record[k] = [str(Path(k) / fn) for fn in df_exp.patch_path]
             if k == 'annotated_zstacks':
-                record[k] = str(Path(k) / self.export_annotated_zstack(subdir, prefix=pr, **kp))
+                record[k] = str(Path(k) / self.export_annotated_zstack(where / subdir, prefix=pr, **kp))
             if k == 'object_classes':
                 for n in self.classification_columns:
-                    fp = subdir / n / (pr + '.tif')
+                    fp = where / subdir / n / (pr + '.tif')
                     write_accessor_data_to_file(fp, self.get_object_class_map(n))
                     record[f'{k}_{n}'] = str(fp)
             if k == 'derived_channels':
                 record[k] = []
                 for di, dacc in enumerate(self.accs_derived):
-                    fp = subdir / f'dc{di:01d}.tif'
+                    fp = where / subdir / f'dc{di:01d}.tif'
                     fp.parent.mkdir(exist_ok=True, parents=True)
                     dacc.export_pyxcz(fp)
                     record[k].append(str(fp))
             if k == 'labels_overlay':
-                fn = self.export_object_identities_overlay_map(subdir, prefix=prefix, **kp)
+                fn = self.export_object_identities_overlay_map(where / subdir, prefix=prefix, **kp)
                 record[k] = str(Path(k) / fn)
 
         # export dataframe and patch masks
-        record = {**record, **self.serialize(where, prefix=prefix)}
+        record = {
+            **record,
+            **self.serialize(
+                where,
+                prefix=prefix,
+                write_patches_to_subdirectory=params.write_patches_to_subdirectory,
+            ),
+        }
 
         return record
 
@@ -1042,25 +1052,29 @@ class RoiSet(object):
 
         return interm
 
-    def serialize(self, where: Path, prefix='roiset', allow_overwrite=True) -> dict:
+    def serialize(self, where: Path, prefix='roiset', allow_overwrite=True, write_patches_to_subdirectory=False) -> dict:
         """
         Export the minimal information needed to recreate RoiSet object, i.e. CSV data file and tight patch masks
         :param where: path of directory in which to write files
         :param prefix: (optional) prefix
         :param allow_overwrite: freely overwrite CSV file of same name if True
+        :param write_patches_to_subdirectory: if True, write all patches to a subdirectory with prefix as name
         :return: nested dict of Path objects describing the locations of export products
         """
         record = {}
         if not self._df.binary_mask.apply(lambda x: np.all(x)).all():  # binary masks aren't just all True
+            subdir = Path('tight_patch_masks')
+            if write_patches_to_subdirectory:
+                subdir = subdir / prefix
             df_exp = self.export_patch_masks(
-                where / 'tight_patch_masks',
+                where / subdir,
                 prefix=prefix,
                 pad_to=None,
                 expanded=False
             )
             # record patch masks paths to dataframe, then save static columns to CSV
             se_pa = df_exp.patch_mask_path.apply(
-                lambda x: str(Path('tight_patch_masks') / x)
+                lambda x: str(subdir / x)
             ).rename('tight_patch_masks_path')
             self._df = self._df.join(se_pa)
             record['tight_patch_masks'] = list(se_pa)
diff --git a/tests/base/test_roiset.py b/tests/base/test_roiset.py
index 9fc1ff74da677b53a0c2b480bffeaf014dc8c00d..e024e68b3dafc2d05e6c13cd8b7eb0a2715e6e02 100644
--- a/tests/base/test_roiset.py
+++ b/tests/base/test_roiset.py
@@ -463,7 +463,10 @@ class TestRoiSetMultichannelProducts(BaseTestRoiSetMonoProducts, unittest.TestCa
         for k, v in res.items():
             if isinstance(v, list):
                 for f in v:
-                    self.assertFalse(Path(f).is_absolute())
+                    try:
+                        self.assertFalse(Path(f).is_absolute())
+                    except Exception as e:
+                        print(e)
                     self.assertTrue((where / f).exists())
             else:
                 self.assertFalse(Path(v).is_absolute())