diff --git a/geomagio/adjusted/transform/LeastSq.py b/geomagio/adjusted/transform/LeastSq.py
index 7f0148737b20060104ae537451f39e3bdc42796c..45c6cb8bc8260b6b4d4b0939ab8c7a33e829c479 100644
--- a/geomagio/adjusted/transform/LeastSq.py
+++ b/geomagio/adjusted/transform/LeastSq.py
@@ -4,10 +4,24 @@ from typing import List, Optional, Tuple
 
 from .Transform import Transform
 
-# TODO: GET_STACKED_ORDINATES SO METHOD CAN BE SHARED
+
 class LeastSq(Transform):
     """Intance of Transform. Applies least squares to generate matrices"""
 
+    def get_stacked_values(self, absolutes, ordinates):
+        # LHS, or dependent variables
+        # [A[0,0], A[1,0], A[2,0], A[0,1], A[1,1], A[2,1], ...]
+        abs_stacked = self.get_stacked_absolutes(absolutes)
+        # RHS, or independent variables
+        # [
+        # [o[0,0], 0, 0, o[0,1], 0, 0, ...],
+        # [0, o[1,0], 0, 0, o[1,1], 0, ...],
+        # [0, 0, o[2,0], 0, 0, o[2,1], ...],
+        # ...
+        # ]
+        ord_stacked = self.get_stacked_ordinates(ordinates)
+        return abs_stacked, ord_stacked
+
     def get_stacked_absolutes(self, absolutes):
         """Formats absolutes for least squares method
 
@@ -21,6 +35,25 @@ class LeastSq(Transform):
         """
         return np.vstack([absolutes[0], absolutes[1], absolutes[2]]).T.ravel()
 
+    def get_stacked_ordinates(self, ordinates):
+        # (reduces degrees of freedom by 4:
+        #  - 4 for the last row of zeros and a one)
+        ord_stacked = np.zeros((12, len(ordinates[0]) * 3))
+        ord_stacked[0, 0::3] = ordinates[0]
+        ord_stacked[1, 0::3] = ordinates[1]
+        ord_stacked[2, 0::3] = ordinates[2]
+        ord_stacked[3, 0::3] = 1.0
+        ord_stacked[4, 1::3] = ordinates[0]
+        ord_stacked[5, 1::3] = ordinates[1]
+        ord_stacked[6, 1::3] = ordinates[2]
+        ord_stacked[7, 1::3] = 1.0
+        ord_stacked[8, 2::3] = ordinates[0]
+        ord_stacked[9, 2::3] = ordinates[1]
+        ord_stacked[10, 2::3] = ordinates[2]
+        ord_stacked[11, 2::3] = 1.0
+
+        return ord_stacked
+
     def get_weighted_values(
         self,
         values: Tuple[List[float], List[float], List[float]],
@@ -50,46 +83,22 @@ class LeastSq(Transform):
         weights: List[float],
     ) -> np.array:
         """Calculates affine with no constraints using least squares."""
-        # LHS, or dependent variables
-        #
-        # [A[0,0], A[1,0], A[2,0], A[0,1], A[1,1], A[2,1], ...]
-        abs_stacked = self.get_stacked_absolutes(absolutes)
-        # RHS, or independent variables
-        # (reduces degrees of freedom by 4:
-        #  - 4 for the last row of zeros and a one)
-        # [
-        # [o[0,0], 0, 0, o[0,1], 0, 0, ...],
-        # [0, o[1,0], 0, 0, o[1,1], 0, ...],
-        # [0, 0, o[2,0], 0, 0, o[2,1], ...],
-        # ...
-        # ]
-        ord_stacked = np.zeros((12, len(ordinates[0]) * 3))
-        ord_stacked[0, 0::3] = ordinates[0]
-        ord_stacked[1, 0::3] = ordinates[1]
-        ord_stacked[2, 0::3] = ordinates[2]
-        ord_stacked[3, 0::3] = 1.0
-        ord_stacked[4, 1::3] = ordinates[0]
-        ord_stacked[5, 1::3] = ordinates[1]
-        ord_stacked[6, 1::3] = ordinates[2]
-        ord_stacked[7, 1::3] = 1.0
-        ord_stacked[8, 2::3] = ordinates[0]
-        ord_stacked[9, 2::3] = ordinates[1]
-        ord_stacked[10, 2::3] = ordinates[2]
-        ord_stacked[11, 2::3] = 1.0
-
+        abs_stacked, ord_stacked = self.get_stacked_values(absolutes, ordinates)
         ord_stacked = self.get_weighted_values(ord_stacked, weights)
         abs_stacked = self.get_weighted_values(abs_stacked, weights)
-
         # regression matrix M that minimizes L2 norm
-        M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T)
+        matrix, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T)
         if rank < 3:
             print("Poorly conditioned or singular matrix, returning NaNs")
             return np.nan * np.ones((4, 4))
+        return self.format_matrix(matrix)
+
+    def format_matrix(self, matrix):
         return np.array(
             [
-                [M_r[0], M_r[1], M_r[2], M_r[3]],
-                [M_r[4], M_r[5], M_r[6], M_r[7]],
-                [M_r[8], M_r[9], M_r[10], M_r[11]],
+                [matrix[0], matrix[1], matrix[2], matrix[3]],
+                [matrix[4], matrix[5], matrix[6], matrix[7]],
+                [matrix[8], matrix[9], matrix[10], matrix[11]],
                 [0.0, 0.0, 0.0, 1.0],
             ]
         )
diff --git a/geomagio/adjusted/transform/Rescale3D.py b/geomagio/adjusted/transform/Rescale3D.py
index 5fdf02ae126605fec05c134998c31b517c91ea05..c55ca8f1e45003296c60b85a59c106cb553f2261 100644
--- a/geomagio/adjusted/transform/Rescale3D.py
+++ b/geomagio/adjusted/transform/Rescale3D.py
@@ -7,14 +7,7 @@ from .LeastSq import LeastSq
 class Rescale3D(LeastSq):
     """Calculates affine using using least squares, constrained to re-scale each axis"""
 
-    def calculate(
-        self,
-        ordinates: Tuple[List[float], List[float], List[float]],
-        absolutes: Tuple[List[float], List[float], List[float]],
-        weights: List[float],
-    ) -> np.array:
-        abs_stacked = self.get_stacked_absolutes(absolutes=absolutes)
-        # RHS, or independent variables
+    def get_stacked_ordinates(self, ordinates):
         # (reduces degrees of freedom by 13:
         #  - 2 for making x independent of y,z;
         #  - 2 for making y,z independent of x;
@@ -26,19 +19,12 @@ class Rescale3D(LeastSq):
         ord_stacked[0, 0::3] = ordinates[0]
         ord_stacked[1, 1::3] = ordinates[1]
         ord_stacked[2, 2::3] = ordinates[2]
+        return ord_stacked
 
-        abs_stacked = self.get_weighted_values(values=abs_stacked, weights=weights)
-        ord_stacked = self.get_weighted_values(values=ord_stacked, weights=weights)
-
-        # regression matrix M that minimizes L2 norm
-        M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T)
-        if rank < 3:
-            print("Poorly conditioned or singular matrix, returning NaNs")
-            return np.nan * np.ones((4, 4))
-
+    def format_matrix(self, matrix):
         return [
-            [M_r[0], 0.0, 0.0, 0.0],
-            [0.0, M_r[1], 0.0, 0.0],
-            [0.0, 0.0, M_r[2], 0.0],
+            [matrix[0], 0.0, 0.0, 0.0],
+            [0.0, matrix[1], 0.0, 0.0],
+            [0.0, 0.0, matrix[2], 0.0],
             [0.0, 0.0, 0.0, 1.0],
         ]
diff --git a/geomagio/adjusted/transform/ShearYZ.py b/geomagio/adjusted/transform/ShearYZ.py
index b413ff58362a6dac9426da8b5c058cd931ca6b9b..dc2e43c213bdb30c976655a7503b79d98157d14a 100644
--- a/geomagio/adjusted/transform/ShearYZ.py
+++ b/geomagio/adjusted/transform/ShearYZ.py
@@ -8,13 +8,7 @@ from .LeastSq import LeastSq
 class ShearYZ(LeastSq):
     """Calculates affine using least squares, constrained to shear y and z, but not x."""
 
-    def calculate(
-        self,
-        ordinates: Tuple[List[float], List[float], List[float]],
-        absolutes: Tuple[List[float], List[float], List[float]],
-        weights: List[float],
-    ) -> np.array:
-        # RHS, or independent variables
+    def get_stacked_ordinates(self, ordinates):
         # (reduces degrees of freedom by 13:
         #  - 2 for making x independent of y,z;
         #  - 1 for making y independent of z;
@@ -27,18 +21,12 @@ class ShearYZ(LeastSq):
         ord_stacked[2, 0::3] = ordinates[0]
         ord_stacked[2, 1::3] = ordinates[1]
         ord_stacked[2, 2::3] = 1.0
-        abs_stacked = self.get_stacked_absolutes(absolutes=absolutes)
-        ord_stacked = self.get_weighted_values(values=ord_stacked, weights=weights)
-        abs_stacked = self.get_weighted_values(values=abs_stacked, weights=weights)
-        # regression matrix M that minimizes L2 norm
-        M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T)
-        if rank < 3:
-            print("Poorly conditioned or singular matrix, returning NaNs")
-            return np.nan * np.ones((4, 4))
+        return ord_stacked
 
+    def format_matrix(self, matrix):
         return [
             [1.0, 0.0, 0.0, 0.0],
-            [M_r[0], 1.0, 0.0, 0.0],
-            [M_r[1], M_r[2], 1.0, 0.0],
+            [matrix[0], 1.0, 0.0, 0.0],
+            [matrix[1], matrix[2], 1.0, 0.0],
             [0.0, 0.0, 0.0, 1.0],
         ]
diff --git a/geomagio/adjusted/transform/TranslateOrigins.py b/geomagio/adjusted/transform/TranslateOrigins.py
index 7b416fa7ecb5e6f0cf3f1744c243336368223f92..69c21915fb007c0bcea79e7c0c6dcb958752a40a 100644
--- a/geomagio/adjusted/transform/TranslateOrigins.py
+++ b/geomagio/adjusted/transform/TranslateOrigins.py
@@ -8,6 +8,17 @@ from .LeastSq import LeastSq
 class TranslateOrigins(LeastSq):
     """Calculates affine using using least squares, constrained to tanslate origins"""
 
+    def get_stacked_values(self, absolutes, ordinates):
+        # LHS, or dependent variables
+        abs_stacked = self.get_stacked_absolutes(absolutes)
+        # subtract ords from abs to force simple translation
+        abs_stacked[0::3] = absolutes[0] - ordinates[0]
+        abs_stacked[1::3] = absolutes[1] - ordinates[1]
+        abs_stacked[2::3] = absolutes[2] - ordinates[2]
+        # RHS, or independent variables
+        ord_stacked = self.get_stacked_ordinates(ordinates)
+        return abs_stacked, ord_stacked
+
     def get_weighted_values(
         self,
         values: Tuple[List[float], List[float], List[float]],
@@ -22,38 +33,17 @@ class TranslateOrigins(LeastSq):
             weights = 1
         return values * weights
 
-    def calculate(
-        self,
-        ordinates: Tuple[List[float], List[float], List[float]],
-        absolutes: Tuple[List[float], List[float], List[float]],
-        weights: List[float],
-    ) -> np.array:
-
-        abs_stacked = self.get_stacked_absolutes(absolutes)
+    def get_stacked_ordinates(self, ordinates):
         ord_stacked = np.zeros((3, len(ordinates[0]) * 3))
-
         ord_stacked[0, 0::3] = 1.0
         ord_stacked[1, 1::3] = 1.0
         ord_stacked[2, 2::3] = 1.0
+        return ord_stacked
 
-        # subtract ords from abs to force simple translation
-        abs_stacked[0::3] = absolutes[0] - ordinates[0]
-        abs_stacked[1::3] = absolutes[1] - ordinates[1]
-        abs_stacked[2::3] = absolutes[2] - ordinates[2]
-
-        # apply weights
-        ord_stacked = self.get_weighted_values(values=ord_stacked, weights=weights)
-        abs_stacked = self.get_weighted_values(values=abs_stacked, weights=weights)
-
-        # regression matrix M that minimizes L2 norm
-        M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T)
-        if rank < 3:
-            print("Poorly conditioned or singular matrix, returning NaNs")
-            return np.nan * np.ones((4, 4))
-
+    def format_matrix(self, matrix):
         return [
-            [1.0, 0.0, 0.0, M_r[0]],
-            [0.0, 1.0, 0.0, M_r[1]],
-            [0.0, 0.0, 1.0, M_r[2]],
+            [1.0, 0.0, 0.0, matrix[0]],
+            [0.0, 1.0, 0.0, matrix[1]],
+            [0.0, 0.0, 1.0, matrix[2]],
             [0.0, 0.0, 0.0, 1.0],
         ]
diff --git a/geomagio/adjusted/transform/ZRotationHScale.py b/geomagio/adjusted/transform/ZRotationHScale.py
index bc08bfc7d744a0f28c746717d71e38be1795802c..a5536bce8202b0a25f40cc6622bef37ec0c181cf 100644
--- a/geomagio/adjusted/transform/ZRotationHScale.py
+++ b/geomagio/adjusted/transform/ZRotationHScale.py
@@ -9,16 +9,7 @@ class ZRotationHscale(LeastSq):
     """Calculates affine using least squares, constrained to rotate about the Z axis
     and apply uniform horizontal scaling."""
 
-    def calculate(
-        self,
-        ordinates: Tuple[List[float], List[float], List[float]],
-        absolutes: Tuple[List[float], List[float], List[float]],
-        weights: List[float],
-    ) -> np.array:
-        # LHS, or dependent variables
-        #
-        abs_stacked = self.get_stacked_absolutes(absolutes)
-        # RHS, or independent variables
+    def get_stacked_ordinates(self, ordinates):
         # (reduces degrees of freedom by 10:
         #  - 2 for making x,y independent of z;
         #  - 2 for making z independent of x,y
@@ -33,19 +24,12 @@ class ZRotationHscale(LeastSq):
         ord_stacked[3, 1::3] = 1.0
         ord_stacked[4, 2::3] = ordinates[2]
         ord_stacked[5, 2::3] = 1.0
+        return ord_stacked
 
-        ord_stacked = self.get_weighted_values(ord_stacked, weights)
-        abs_stacked = self.get_weighted_values(abs_stacked, weights)
-
-        # regression matrix M that minimizes L2 norm
-        M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T)
-        if rank < 3:
-            print("Poorly conditioned or singular matrix, returning NaNs")
-            return np.nan * np.ones((4, 4))
-
+    def format_matrix(self, matrix):
         return [
-            [M_r[0], M_r[1], 0.0, M_r[2]],
-            [-M_r[1], M_r[0], 0.0, M_r[3]],
-            [0.0, 0.0, M_r[4], M_r[5]],
+            [matrix[0], matrix[1], 0.0, matrix[2]],
+            [-matrix[1], matrix[0], 0.0, matrix[3]],
+            [0.0, 0.0, matrix[4], matrix[5]],
             [0.0, 0.0, 0.0, 1.0],
         ]
diff --git a/geomagio/adjusted/transform/ZRotationHScaleZBaseline.py b/geomagio/adjusted/transform/ZRotationHScaleZBaseline.py
index 0be5b249f609dc467516f2b6cdfc374fa1ada8dc..569786afcbf5be6f58704d2f9ab50a80158b2c13 100644
--- a/geomagio/adjusted/transform/ZRotationHScaleZBaseline.py
+++ b/geomagio/adjusted/transform/ZRotationHScaleZBaseline.py
@@ -9,13 +9,16 @@ class ZRotationHscaleZbaseline(LeastSq):
     """Calculates affine using least squares, constrained to rotate about the Z axis,
     apply a uniform horizontal scaling, and apply a baseline shift for the Z axis."""
 
-    def calculate(
-        self,
-        ordinates: Tuple[List[float], List[float], List[float]],
-        absolutes: Tuple[List[float], List[float], List[float]],
-        weights: List[float],
-    ) -> np.array:
+    def get_stacked_values(self, absolutes, ordinates):
+        # LHS, or dependent variables
+        abs_stacked = self.get_stacked_absolutes(absolutes)
+        # subtract z_o from z_a to force simple z translation
+        abs_stacked[2::3] = absolutes[2] - ordinates[2]
         # RHS, or independent variables
+        ord_stacked = self.get_stacked_ordinates(ordinates)
+        return abs_stacked, ord_stacked
+
+    def get_stacked_ordinates(self, ordinates):
         # (reduces degrees of freedom by 13:
         #  - 2 for making x,y independent of z;
         #  - 2 for making z independent of x,y;
@@ -29,23 +32,12 @@ class ZRotationHscaleZbaseline(LeastSq):
         ord_stacked[1, 0::3] = ordinates[1]
         ord_stacked[1, 1::3] = -ordinates[0]
         ord_stacked[2, 2::3] = 1.0
+        return ord_stacked
 
-        # subtract z_o from z_a to force simple z translation
-        abs_stacked = self.get_stacked_absolutes(absolutes)
-        abs_stacked[2::3] = absolutes[2] - ordinates[2]
-
-        abs_stacked = self.get_weighted_values(values=abs_stacked, weights=weights)
-        ord_stacked = self.get_weighted_values(values=ord_stacked, weights=weights)
-
-        # regression matrix M that minimizes L2 norm
-        M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T)
-        if rank < 3:
-            print("Poorly conditioned or singular matrix, returning NaNs")
-            return np.nan * np.ones((4, 4))
-
+    def format_matrix(self, matrix):
         return [
-            [M_r[0], M_r[1], 0.0, 0.0],
-            [-M_r[1], M_r[0], 0.0, 0.0],
-            [0.0, 0.0, 1.0, M_r[2]],
+            [matrix[0], matrix[1], 0.0, 0.0],
+            [-matrix[1], matrix[0], 0.0, 0.0],
+            [0.0, 0.0, 1.0, matrix[2]],
             [0.0, 0.0, 0.0, 1.0],
         ]
diff --git a/geomagio/adjusted/transform/ZRotationShear.py b/geomagio/adjusted/transform/ZRotationShear.py
index 322eb8dbf226c9bf789be0d0cd6334c4005bbf24..693cbb4152b5081cdc8806349dd58e6e02c6c286 100644
--- a/geomagio/adjusted/transform/ZRotationShear.py
+++ b/geomagio/adjusted/transform/ZRotationShear.py
@@ -6,17 +6,7 @@ from .LeastSq import LeastSq
 
 
 class ZRotationShear(LeastSq):
-    def calculate(
-        self,
-        ordinates: Tuple[List[float], List[float], List[float]],
-        absolutes: Tuple[List[float], List[float], List[float]],
-        weights: List[float],
-    ) -> np.array:
-        """Calculates affine using least squares, constrained to rotate about the Z axis."""
-        # LHS, or dependent variables
-        #
-        abs_stacked = self.get_stacked_absolutes(absolutes)
-        # RHS, or independent variables
+    def get_stacked_ordinates(self, ordinates):
         # (reduces degrees of freedom by 8:
         #  - 2 for making x,y independent of z;
         #  - 2 for making z independent of x,y
@@ -30,19 +20,12 @@ class ZRotationShear(LeastSq):
         ord_stacked[5, 1::3] = 1.0
         ord_stacked[6, 2::3] = ordinates[2]
         ord_stacked[7, 2::3] = 1.0
+        return ord_stacked
 
-        ord_stacked = self.get_weighted_values(ord_stacked, weights)
-        abs_stacked = self.get_weighted_values(abs_stacked, weights)
-
-        # regression matrix M that minimizes L2 norm
-        M_r, res, rank, sigma = spl.lstsq(ord_stacked.T, abs_stacked.T)
-        if rank < 3:
-            print("Poorly conditioned or singular matrix, returning NaNs")
-            return np.nan * np.ones((4, 4))
-
+    def format_matrix(self, matrix):
         return [
-            [M_r[0], M_r[1], 0.0, M_r[2]],
-            [M_r[3], M_r[4], 0.0, M_r[5]],
-            [0.0, 0.0, M_r[6], M_r[7]],
+            [matrix[0], matrix[1], 0.0, matrix[2]],
+            [matrix[3], matrix[4], 0.0, matrix[5]],
+            [0.0, 0.0, matrix[6], matrix[7]],
             [0.0, 0.0, 0.0, 1.0],
         ]