Index: trunk/psastro/src/psastroLoadCrosstalk.c
===================================================================
--- trunk/psastro/src/psastroLoadCrosstalk.c	(revision 41434)
+++ trunk/psastro/src/psastroLoadCrosstalk.c	(revision 41551)
@@ -85,9 +85,6 @@
   }
   // Activate the reference mask to generate an FPA structure we can use to map stars down to cells
-
   pmFPAfileActivate (config->files, false, NULL);
   pmFPAfileActivate (config->files, true, "PSASTRO.REFMASK");
-
-  //  pmFPA *refFPA = refMask->fpa;
 
   if (!pmFPAfileIOChecks (config, view, PM_FPA_BEFORE)) ESCAPE;
@@ -108,4 +105,13 @@
   SPIKE_MAX_MAG = psMetadataLookupF32(&status, recipe, "REFSTAR_MASK_BLEED_MAG_MAX");
   SPIKE_MAX_MAG += MagOffset;
+
+  //we will use one of the new keywords to differentiate between an old and new style crosstalk treatment
+  float crossCheck = 0;
+  char *crossFile = psMetadataLookupStr (&status, recipe, "CROSSTALK_FILE");
+  if (!strcasecmp(crossFile, "NONE")) {
+      psLogMsg ("psastro", PS_LOG_INFO, "Assuming old-style crostalk masking, with small number of rules");
+      crossCheck = 1;
+  }
+
   //  psTraceSetLevel("psastro.crosstalk",2);  
   psTrace("psastro.crosstalk",2,"%f %f %f %f\n",zeropt,exptime,MAX_MAG,MagOffset);
@@ -124,4 +130,5 @@
     int X = chipName[2] - '0';
     int Y = chipName[3] - '0';
+    int chipNum = (X*10)+Y ;
 
     // Read each cell (at this stage, we should only have one of them)
@@ -135,390 +142,645 @@
           if (! readout->data_exists) { continue; }
 
-          // If this chip doesn't crosstalk, skip to the next one.
-          if (! ((X == 2)||(X == 5))) {
-            psTrace ("psastro.crosstalk",2,"Chip (%d%d) not a known crosstalk source.",X,Y);
-            continue;
-          }
-
-          // To check for the presence of crosstalk we first make use the actual detections on this image.
-          // That way we can include things like movers creating crosstalk features.
-          psArray *calstars = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.CALSTARS");
-          if (calstars == NULL) { continue; }
-
-          for (int i = 0; i < calstars->n; i++) {
-            pmAstromObj *cal = calstars->data[i];
-
-            if (cal->Mag > INSTR_MAX_MAG) {
+          //old crosstalk method, with limited hard-coded rules
+          if(crossCheck) {
+            // If this chip doesn't crosstalk, skip to the next one.
+            if (! ((X == 2)||(X == 5))) {
+              psTrace ("psastro.crosstalk",2,"Chip (%d%d) not a known crosstalk source.",X,Y);
               continue;
             }
 
-            // Identify which cell holds the star
-            pmChip *CTsourceChip = refChip;
-            pmCell *CTsourceCell = pmCellInChip(refChip,cal->chip->x,cal->chip->y);
-
-            if (!CTsourceCell) {
-              continue;
+            // To check for the presence of crosstalk we first make use the actual detections on this image.
+            // That way we can include things like movers creating crosstalk features.
+            psArray *calstars = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.CALSTARS");
+            if (calstars == NULL) { continue; }
+
+            for (int i = 0; i < calstars->n; i++) {
+              pmAstromObj *cal = calstars->data[i];
+
+              if (cal->Mag > INSTR_MAX_MAG) { continue; }
+
+              // Identify which cell holds the star
+              pmChip *CTsourceChip = refChip;
+              pmCell *CTsourceCell = pmCellInChip(refChip,cal->chip->x,cal->chip->y);
+
+              if (!CTsourceCell) { continue; }
+
+              psTrace ("psastro.crosstalk",2,"DETEC: %d %f :: %f %f\n",
+                       i,cal->Mag, cal->chip->x,cal->chip->y);
+
+              const char *cellName = psMetadataLookupStr(NULL,CTsourceCell->concepts, "CELL.NAME");
+              int U = cellName[2] - '0';
+              int V = cellName[3] - '0';
+
+              int Xt = X,Yt = Y,Ut = U,Vt = V;
+              float x_cell,y_cell;
+              float x_t_cell,y_t_cell;
+  
+              float x_t_chip,y_t_chip;
+	      // int faint_ct = 0; NOTE: not currently used
+              pmCellCoordsForChip(&x_cell,&y_cell,CTsourceCell,cal->chip->x,cal->chip->y);
+
+              x_t_cell = x_cell;
+              y_t_cell = y_cell;
+
+	      // 2020-10-21 TdB: Here is the list of known cross talks from the bright star analysis:
+              // The relationships work using OTA"XY"XY"UV"
+	      // Inter-chip
+	      // OTA2yXY3v => OTA3yXY3v
+	      // OTA4yXY3v <= OTA5yXY3v
+	      // Intra-chip
+	      // OTA2yXY5v <=> OTA2yXY6v
+	      // OTA5yXY5v <=> OTA5yXY6v
+	      // One way fainter
+	      // OTA2yXY7v => OTA3yXY2v
+	      // OTA5yXY7v => OTA4yXY2v
+              // Determine if this combination of chip and cell produces a crosstalk artifact
+              if ((X == 2)&&(! ((U == 3)||(U == 5)||(U == 6)||(U == 7)))) {
+                psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
+	        psTrace ("psastro.crosstalk",2,"t1: %d t2: %d",
+		         (X == 2),
+	  	         (! ((U == 3)||(U == 5)||(U == 6)||(U == 7))));
+                continue;
+              }
+              if ((X == 5)&&(! ((U == 3)||(U == 5)||(U == 6)||(U == 7)))) {
+                psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
+                continue;
+              }
+
+              // Calculate destination positions
+              if (X == 2) {
+                if (U == 3) {
+                  Xt = 3;
+                }
+                if (U == 5) {
+                  Ut = 6;
+                }
+                if (U == 6) {
+                  Ut = 5;
+                }
+	        if (U == 7) {
+		  Xt = 3;
+		  Ut = 2;
+		  // faint_ct = 1; NOTE: not currently used
+	        }
+              }
+              if (X == 5) {
+                if (U == 3) {
+                  Xt = 4;
+                }
+                if (U == 5) {
+                  Ut = 6;
+                }
+                if (U == 6) {
+                  Ut = 5;
+                }
+	        if (U == 7) {
+		  Xt = 4;
+		  Ut = 2;
+		  // faint_ct = 1; NOTE: not currently used
+  	        }
+              }
+
+              // Convert target cell coordinates to target chip coordinates
+              psString targetChipName = NULL;
+              psStringAppend(&targetChipName,"XY%d%d",Xt,Yt);
+              psString targetCellName = NULL;
+              psStringAppend(&targetCellName,"xy%d%d",Ut,Vt);
+
+              psTrace ("psastro.crosstalk",2,"CTsource from DETEC @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f [%s %s]",
+                       X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,
+                       targetChipName,targetCellName);
+
+              pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
+              if (!CTtargetCell) continue;
+
+              pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
+
+              psTrace ("psastro.crosstalk",2,"CTsource from DETEC @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f ChipLoc: (%f,%f)",
+                       X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
+
+              // Hunt down the readout for the target, and save the chip position and magnitude of source star.
+              pmChip *targetChip = getChipByName(fpa,targetChipName);
+              if (!targetChip) continue;
+              if (!targetChip->cells) continue;
+              if (!targetChip->cells->n) continue;
+
+              pmCell *targetCell = targetChip->cells->data[0];
+              if (!targetCell) continue;
+              if (!targetCell->readouts) continue;
+              if (!targetCell->readouts->n) continue;
+              pmReadout *targetReadout = targetCell->readouts->data[0];
+              if (!targetReadout) continue;
+
+              pmAstromObj *crosstalk = pmAstromObjAlloc();
+	    
+              crosstalk->Mag = cal->Mag;
+              crosstalk->chip->x = x_t_chip;
+              crosstalk->chip->y = y_t_chip;
+
+              psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS");
+              if (crosstalks == NULL) {
+                crosstalks = psArrayAllocEmpty(100);
+                if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
+                  psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
+                  goto escape;
+                }
+                psFree(crosstalks);
+              }
+              psArrayAdd(crosstalks,100,crosstalk);
+	    
+              psFree(targetChipName);
+              psFree(targetCellName);
+              psFree(crosstalk);
+
+	      // Determine if we need to add a spike mask.
+	      // CZW 2014-04-15 I'm not adding the new faint CT to this operation.  There's no evidence they produce such things.
+	      if (cal->Mag < SPIKE_MAX_MAG) {
+	        if ((X == 2)&&(! ((U == 3)||(U == 5)||(U == 6)))) {
+		  psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
+		  continue;
+	        }
+	        if ((X == 5)&&(! ((U == 3)||(U == 5)||(U == 6)))) {
+		  psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
+		  continue;
+	        }
+	      
+	        Xt = X;
+	        Yt = Y;
+	        Vt = V;
+	      
+	        for (Ut = 0; Ut < 8; Ut++) {
+		  psString targetChipName = NULL;
+		  psStringAppend(&targetChipName,"XY%d%d",Xt,Yt);
+		  psString targetCellName = NULL;
+		  psStringAppend(&targetCellName,"xy%d%d",Ut,Vt);
+		
+		  psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f [%s %s]",
+			   X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,
+			   targetChipName,targetCellName);
+		
+		  pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
+		  if (!CTtargetCell) continue;
+		
+		  pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
+
+		  psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f ChipLoc: (%f,%f)",
+		  	   X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
+		
+		  // Hunt down the readout for the target, and save the chip position and magnitude of source star.
+		  pmChip *targetChip = getChipByName(fpa,targetChipName);
+		  if (!targetChip) continue;
+		  if (!targetChip->cells) continue;
+		  if (!targetChip->cells->n) continue;
+		  
+		  pmCell *targetCell = targetChip->cells->data[0];
+		  if (!targetCell) continue;
+		  if (!targetCell->readouts) continue;
+		  if (!targetCell->readouts->n) continue;
+		  pmReadout *targetReadout = targetCell->readouts->data[0];
+		  if (!targetReadout) continue;
+		
+		  pmAstromObj *crosstalk = pmAstromObjAlloc();
+		
+		  crosstalk->Mag = cal->Mag;
+		  crosstalk->chip->x = x_t_chip;
+		  crosstalk->chip->y = y_t_chip;
+		
+		  psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS.SPIKES");
+		  if (crosstalks == NULL) {
+		    crosstalks = psArrayAllocEmpty(100);
+		    if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS.SPIKES", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
+		      psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
+		      goto escape;
+		    }
+		    psFree(crosstalks);
+		  }
+		  psArrayAdd(crosstalks,100,crosstalk);
+		
+		  psFree(targetChipName);
+		  psFree(targetCellName);
+		  psFree(crosstalk);
+	        }
+	      } // End satspike crosstalks
+
             }
-
-            psTrace ("psastro.crosstalk",2,"DETEC: %d %f :: %f %f\n",
-                     i,cal->Mag, cal->chip->x,cal->chip->y);
-
-            const char *cellName = psMetadataLookupStr(NULL,CTsourceCell->concepts, "CELL.NAME");
-            int U = cellName[2] - '0';
-            int V = cellName[3] - '0';
-
-            int Xt = X,Yt = Y,Ut = U,Vt = V;
-            float x_cell,y_cell;
-            float x_t_cell,y_t_cell;
-
-            float x_t_chip,y_t_chip;
-	    // int faint_ct = 0; NOTE: not currently used
-            pmCellCoordsForChip(&x_cell,&y_cell,CTsourceCell,cal->chip->x,cal->chip->y);
-
-            x_t_cell = x_cell;
-            y_t_cell = y_cell;
-
-	    // 2020-10-21 TdB: Here is the list of known cross talks from the bright star analysis:
-            // The relationships work using OTA"XY"XY"UV"
-	    // Inter-chip
-	    // OTA2yXY3v => OTA3yXY3v
-	    // OTA4yXY3v <= OTA5yXY3v
-	    // Intra-chip
-	    // OTA2yXY5v <=> OTA2yXY6v
-	    // OTA5yXY5v <=> OTA5yXY6v
-	    // One way fainter
-	    // OTA2yXY7v => OTA3yXY2v
-	    // OTA5yXY7v => OTA4yXY2v
-            // Determine if this combination of chip and cell produces a crosstalk artifact
-            if ((X == 2)&&(! ((U == 3)||(U == 5)||(U == 6)||(U == 7)))) {
-              psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
-	      psTrace ("psastro.crosstalk",2,"t1: %d t2: %d",
-		       (X == 2),
-		       (! ((U == 3)||(U == 5)||(U == 6)||(U == 7))));
-              continue;
+          }
+
+          //-----------------------------------------------------------------
+          //-----------------------------------------------------------------
+          //new style crostalk masking, with crosstalk rules from the recipes
+          if(!crossCheck) {
+            // load ghost model metadata structure
+            psMetadata *crossModel = NULL;
+            if (!pmConfigFileRead (&crossModel, crossFile, "CROSS MODEL")) {
+	          psError(PSASTRO_ERR_CONFIG, true, "Trouble loading crosstalk rules file");
+                  return false;
             }
-            if ((X == 5)&&(! ((U == 3)||(U == 5)||(U == 6)||(U == 7)))) {
-              psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
-              continue;
+
+             // get the set of crosstalk rules (CROSSTALK.RULE is a MULTI of METADATA items)
+            psMetadataItem *crossRules = psMetadataLookup (crossModel, "CROSSTALK.RULE");
+            if (crossRules->type != PS_DATA_METADATA_MULTI) {
+                  psWarning ("CROSSTALK.RULE is not a MULTI\n");
+                  return true;
             }
 
-            // Calculate destination positions
-            if (X == 2) {
-              if (U == 3) {
-                Xt = 3;
-              }
-              if (U == 5) {
-                Ut = 6;
-              }
-              if (U == 6) {
-                Ut = 5;
-              }
-	      if (U == 7) {
-		Xt = 3;
-		Ut = 2;
-		// faint_ct = 1; NOTE: not currently used
-	      }
-            }
-            if (X == 5) {
-              if (U == 3) {
-                Xt = 4;
-              }
-              if (U == 5) {
-                Ut = 6;
-              }
-              if (U == 6) {
-                Ut = 5;
-              }
-	      if (U == 7) {
-		Xt = 4;
-		Ut = 2;
-		// faint_ct = 1; NOTE: not currently used
-	      }
-            }
-
-            // Convert target cell coordinates to target chip coordinates
-            psString targetChipName = NULL;
-            psStringAppend(&targetChipName,"XY%d%d",Xt,Yt);
-            psString targetCellName = NULL;
-            psStringAppend(&targetCellName,"xy%d%d",Ut,Vt);
-
-            psTrace ("psastro.crosstalk",2,"CTsource from DETEC @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f [%s %s]",
-                     X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,
-                     targetChipName,targetCellName);
-
-
-            pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
-            if (!CTtargetCell) continue;
-
-            pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
-
-            psTrace ("psastro.crosstalk",2,"CTsource from DETEC @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f ChipLoc: (%f,%f)",
-                     X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
-
-            // Hunt down the readout for the target, and save the chip position and magnitude of source star.
-            pmChip *targetChip = getChipByName(fpa,targetChipName);
-            if (!targetChip) continue;
-            if (!targetChip->cells) continue;
-            if (!targetChip->cells->n) continue;
-
-            pmCell *targetCell = targetChip->cells->data[0];
-            if (!targetCell) continue;
-            if (!targetCell->readouts) continue;
-            if (!targetCell->readouts->n) continue;
-            pmReadout *targetReadout = targetCell->readouts->data[0];
-            if (!targetReadout) continue;
-
-            pmAstromObj *crosstalk = pmAstromObjAlloc();
-	    
-            crosstalk->Mag = cal->Mag;
-            crosstalk->chip->x = x_t_chip;
-            crosstalk->chip->y = y_t_chip;
-
-            psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS");
-            if (crosstalks == NULL) {
-              crosstalks = psArrayAllocEmpty(100);
-              if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
-                psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
-                goto escape;
-              }
-              psFree(crosstalks);
-            }
-            psArrayAdd(crosstalks,100,crosstalk);
-	    
-            psFree(targetChipName);
-            psFree(targetCellName);
-            psFree(crosstalk);
-          }
-
-
-          // We also want to use the refstars to check for crosstalk. In particular, the detections 
-          // do not do well for bright stars, and saturated detections will underestimate the size of the crostalk
-          // Get the array of reference stars we're concerned with.
-          psArray *refstars = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.REFSTARS");
-          if (refstars == NULL) { return(true); }
-
-          // Check each reference star
-          for (int i = 0; i < refstars->n; i++) {
-	    // This is the source of the ct.
-            pmAstromObj *ref = refstars->data[i];
-
-            if (ref->Mag > MAX_MAG) {
-              continue;
-            }
-
-            // Identify which cell holds the star
-            pmChip *CTsourceChip = refChip;
-            pmCell *CTsourceCell = pmCellInChip(refChip,ref->chip->x,ref->chip->y);
-
-            if (!CTsourceCell) {
-              continue;
-            }
-
-            psTrace ("psastro.crosstalk",2,"REF: %d %f (%f %f) %f %f :: %f %f\n",
-                     i,ref->Mag, ref->sky->r,ref->sky->d, ref->FP->x,ref->FP->y, ref->chip->x,ref->chip->y);
-
-            const char *cellName = psMetadataLookupStr(NULL,CTsourceCell->concepts, "CELL.NAME");
-            int U = cellName[2] - '0';
-            int V = cellName[3] - '0';
-
-            int Xt = X,Yt = Y,Ut = U,Vt = V;
-            float x_cell,y_cell;
-            float x_t_cell,y_t_cell;
-
-            float x_t_chip,y_t_chip;
-	    // int faint_ct = 0; NOTE: not currently used
-            pmCellCoordsForChip(&x_cell,&y_cell,CTsourceCell,ref->chip->x,ref->chip->y);
-
-            x_t_cell = x_cell;
-            y_t_cell = y_cell;
-
-	    // 2020-10-21 TdB: Here is the list of known cross talks from the bright star analysis:
-            // The relationships work using OTA"XY"XY"UV"
-	    // Inter-chip
-	    // OTA2yXY3v => OTA3yXY3v
-	    // OTA4yXY3v <= OTA5yXY3v
-	    // Intra-chip
-	    // OTA2yXY5v <=> OTA2yXY6v
-	    // OTA5yXY5v <=> OTA5yXY6v
-	    // One way fainter
-	    // OTA2yXY7v => OTA3yXY2v
-	    // OTA5yXY7v => OTA4yXY2v
-            // Determine if this combination of chip and cell produces a crosstalk artifact
-            if ((X == 2)&&(! ((U == 3)||(U == 5)||(U == 6)||(U == 7)))) {
-              psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
-	      psTrace ("psastro.crosstalk",2,"t1: %d t2: %d",
-		       (X == 2),
-		       (! ((U == 3)||(U == 5)||(U == 6)||(U == 7))));
-              continue;
-            }
-            if ((X == 5)&&(! ((U == 3)||(U == 5)||(U == 6)||(U == 7)))) {
-              psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
-              continue;
-            }
-
-            // Calculate destination positions
-            if (X == 2) {
-              if (U == 3) {
-                Xt = 3;
-              }
-              if (U == 5) {
-                Ut = 6;
-              }
-              if (U == 6) {
-                Ut = 5;
-              }
-	      if (U == 7) {
-		Xt = 3;
-		Ut = 2;
-		// faint_ct = 1; NOTE: not currently used
-	      }
-            }
-            if (X == 5) {
-              if (U == 3) {
-                Xt = 4;
-              }
-              if (U == 5) {
-                Ut = 6;
-              }
-              if (U == 6) {
-                Ut = 5;
-              }
-	      if (U == 7) {
-		Xt = 4;
-		Ut = 2;
-		// faint_ct = 1; NOTE: not currently used
-	      }
-            }
-
-            // Convert target cell coordinates to target chip coordinates
-            psString targetChipName = NULL;
-            psStringAppend(&targetChipName,"XY%d%d",Xt,Yt);
-            psString targetCellName = NULL;
-            psStringAppend(&targetCellName,"xy%d%d",Ut,Vt);
-
-            psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f [%s %s]",
-                     X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,
-                     targetChipName,targetCellName);
-
-            pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
-            if (!CTtargetCell) continue;
-
-            pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
-
-            psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f ChipLoc: (%f,%f)",
-                     X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
-
-            // Hunt down the readout for the target, and save the chip position and magnitude of source star.
-            pmChip *targetChip = getChipByName(fpa,targetChipName);
-            if (!targetChip) continue;
-            if (!targetChip->cells) continue;
-            if (!targetChip->cells->n) continue;
-
-            pmCell *targetCell = targetChip->cells->data[0];
-            if (!targetCell) continue;
-            if (!targetCell->readouts) continue;
-            if (!targetCell->readouts->n) continue;
-            pmReadout *targetReadout = targetCell->readouts->data[0];
-            if (!targetReadout) continue;
-
-            pmAstromObj *crosstalk = pmAstromObjAlloc();
-	    
-            crosstalk->Mag = ref->Mag - MagOffset;
-            crosstalk->chip->x = x_t_chip;
-            crosstalk->chip->y = y_t_chip;
-            crosstalk->chip->y = y_t_chip;
-
-            psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS");
-            if (crosstalks == NULL) {
-              crosstalks = psArrayAllocEmpty(100);
-              if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
-                psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
-                goto escape;
-              }
-              psFree(crosstalks);
-            }
-            psArrayAdd(crosstalks,100,crosstalk);
-	    
-            psFree(targetChipName);
-            psFree(targetCellName);
-            psFree(crosstalk);
-
-	    // Determine if we need to add a spike mask.
-	    // CZW 2014-04-15 I'm not adding the new faint CT to this operation.  There's no evidence they produce such things.
-/* 	    psWarning("BLAH: %g %g %g\n",ref->Mag,MagOffset,SPIKE_MAX_MAG); */
-	    if (ref->Mag < SPIKE_MAX_MAG) {
-	      if ((X == 2)&&(! ((U == 3)||(U == 5)||(U == 6)))) {
-		psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
+            pmDetEff *de = psMetadataLookupPtr(NULL, readout->analysis, PM_DETEFF_ANALYSIS); // Detection efficiency
+            if (isnan(de->magRef)) { continue; }
+
+	    // find the CROSSTALK.RUKE this chip lands in (if any)
+	    psListIterator *crossIter = psListIteratorAlloc(crossRules->data.list, PS_LIST_HEAD, false);
+	    psMetadataItem *crossItem = NULL;
+	    while ((crossItem = psListGetAndIncrement (crossIter))) {
+	      if (crossItem->type != PS_DATA_METADATA) {
+		psWarning ("CROSSTALK.RULE entry is not a metadata folder");
 		continue;
 	      }
-	      if ((X == 5)&&(! ((U == 3)||(U == 5)||(U == 6)))) {
-		psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
+
+	      int crossChip = psMetadataLookupS32 (&status, crossItem->data.md, "CHIP.SRC");
+	      int crossCell = psMetadataLookupS32 (&status, crossItem->data.md, "CELL.SRC");
+	      int crossChipOffset = psMetadataLookupS32 (&status, crossItem->data.md, "CHIP.OFFSET");
+	      int crossCellOffset = psMetadataLookupS32 (&status, crossItem->data.md, "CELL.OFFSET");
+	      float crossMagOff = psMetadataLookupF32 (&status, crossItem->data.md, "CROSS.MAGDIFF");
+              psLogMsg ("psastro", PS_LOG_INFO, "RULE: %d %d %d %d %f ",
+                       crossChip,crossCell,crossChipOffset,crossCellOffset,crossMagOff);
+	      if (!status) {
+		psWarning ("CROSSTALK.RULE entry is missing necessary entry");
 		continue;
 	      }
+
+              if (!(X == crossChip)) {
+                psTrace ("psastro.crosstalk",2,"Chip (%d%d) not a known crosstalk source.",X,Y); 
+                psLogMsg ("psastro", PS_LOG_INFO, "Chip (%d%d) not a known crosstalk source.",X,Y);
+                continue;
+              }
+
+              //the source star needs to be bright enough to produce a crosstalk feature on the target chip/cell that is above the refmag
+              float INSTR_CROSS_MAX_MAG = de->magRef - crossMagOff;
+              float CROSS_MAX_MAG = INSTR_CROSS_MAX_MAG + MagOffset;
+
+              // To check for the presence of crosstalk we first make use the actual detections on this image.
+              // That way we can include things like movers creating crosstalk features.
+              psArray *calstars = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.CALSTARS");
+              if (calstars == NULL) { continue; }
+
+              for (int i = 0; i < calstars->n; i++) {
+                pmAstromObj *cal = calstars->data[i];
+                //kick out stars too faint to produce crosstalk with this rule
+                if (cal->Mag > INSTR_CROSS_MAX_MAG) { continue; }
+
+                // Identify which cell holds the star
+                pmChip *CTsourceChip = refChip;
+                pmCell *CTsourceCell = pmCellInChip(refChip,cal->chip->x,cal->chip->y);
+                if (!CTsourceCell) { continue; }
+
+                psTrace ("psastro.crosstalk",2,"DETEC: %d %f :: %f %f\n",
+                       i,cal->Mag, cal->chip->x,cal->chip->y);
+
+                const char *cellName = psMetadataLookupStr(NULL,CTsourceCell->concepts, "CELL.NAME");
+                int U = cellName[2] - '0';
+                int V = cellName[3] - '0';
+                int cellNum = (U*10)+V ;
+
+                float x_cell,y_cell;
+                float x_t_cell,y_t_cell;
+  
+                float x_t_chip,y_t_chip;
+	        // int faint_ct = 0; NOTE: not currently used
+                pmCellCoordsForChip(&x_cell,&y_cell,CTsourceCell,cal->chip->x,cal->chip->y);
+
+                x_t_cell = x_cell;
+                y_t_cell = y_cell;
+
+                if (! (U == crossCell) ) {
+                  psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
+                  continue;
+                }
+
+                int chipTarget = chipNum + crossChipOffset ; 
+                int cellTarget = cellNum + crossCellOffset ; 
+
+                // Convert target cell coordinates to target chip coordinates
+                psString targetChipName = NULL;
+                if(chipTarget > 8) {
+                  psStringAppend(&targetChipName,"XY%2d",chipTarget);
+                }
+                if(chipTarget < 8) {
+                  psStringAppend(&targetChipName,"XY0%1d",chipTarget);
+                }
+                psString targetCellName = NULL;
+                if(cellTarget > 8) {
+                  psStringAppend(&targetCellName,"xy%2d",cellTarget);
+                }
+                if(cellTarget < 8) {
+                  psStringAppend(&targetCellName,"xy0%1d",cellTarget);
+                }
+
+                psTrace ("psastro.crosstalk",2,"CTsource from DETEC @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%2dxy%2d@%f,%f [%s %s]",
+                       X,Y,U,V,x_cell,y_cell,chipTarget,cellTarget,x_t_cell,y_t_cell,
+                       targetChipName,targetCellName);
+
+                pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
+                if (!CTtargetCell) continue;
+
+                pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
+
+                psTrace ("psastro.crosstalk",2,"CTsource from DETEC @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%2dxy%2d@%f,%f ChipLoc: (%f,%f)",
+                       X,Y,U,V,x_cell,y_cell,chipTarget,cellTarget,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
+
+                // Hunt down the readout for the target, and save the chip position and magnitude of source star.
+                pmChip *targetChip = getChipByName(fpa,targetChipName);
+                if (!targetChip) continue;
+                if (!targetChip->cells) continue;
+                if (!targetChip->cells->n) continue;
+
+                pmCell *targetCell = targetChip->cells->data[0];
+                if (!targetCell) continue;
+                if (!targetCell->readouts) continue;
+                if (!targetCell->readouts->n) continue;
+                pmReadout *targetReadout = targetCell->readouts->data[0];
+                if (!targetReadout) continue;
+
+                //check if the crosstalk is above the target chip background level
+                pmDetEff *tarde = psMetadataLookupPtr(NULL, targetReadout->analysis, PM_DETEFF_ANALYSIS); // Detection efficiency
+                if (isnan(tarde->magRef)) { continue; }
+
+                float TARGET_CROSS_MAX_MAG = tarde->magRef-crossMagOff;
+
+                if (cal->Mag > TARGET_CROSS_MAX_MAG) { continue; }
+
+                pmAstromObj *crosstalk = pmAstromObjAlloc();
+
+                psLogMsg ("psastro", PS_LOG_INFO, "CTsource from DETEC @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%2dxy%2d@%f,%f ChipLoc: (%f,%f) %f",
+                       X,Y,U,V,cal->chip->x,cal->chip->y,chipTarget,cellTarget,x_t_cell,y_t_cell,x_t_chip,y_t_chip,cal->Mag);
+	    
+                crosstalk->Mag = cal->Mag;
+                crosstalk->chip->x = x_t_chip;
+                crosstalk->chip->y = y_t_chip;
+
+                psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS");
+                if (crosstalks == NULL) {
+                  crosstalks = psArrayAllocEmpty(100);
+                  if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
+                    psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
+                    goto escape;
+                  }
+                  psFree(crosstalks);
+                }
+                psArrayAdd(crosstalks,100,crosstalk);
+	    
+                psFree(targetChipName);
+                psFree(targetCellName);
+                psFree(crosstalk);
+
+	        // Determine if we need to add a spike mask.
+                // TdB20210304: This should not be relevant for faint crosstalk rules. Do this rather ad hoc right now by placing a limit at 8 mags of difference
+                if( crossMagOff > 8.) { continue; }
+	        if (cal->Mag < SPIKE_MAX_MAG) {	      
+	          int Xt = X;
+	          int Yt = Y;
+	          int Vt = V;
 	      
-	      Xt = X;
-	      Yt = Y;
-	      Vt = V;
+	          for (int Ut = 0; Ut < 8; Ut++) {
+		    psString targetChipName = NULL;
+		    psStringAppend(&targetChipName,"XY%d%d",Xt,Yt);
+		    psString targetCellName = NULL;
+		    psStringAppend(&targetCellName,"xy%d%d",Ut,Vt);
+		
+		    psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f [%s %s]",
+			   X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,
+			   targetChipName,targetCellName);
+		
+		    pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
+		    if (!CTtargetCell) continue;
+		
+		    pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
+
+		    psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f ChipLoc: (%f,%f)",
+		  	   X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
+		
+		    // Hunt down the readout for the target, and save the chip position and magnitude of source star.
+		    pmChip *targetChip = getChipByName(fpa,targetChipName);
+		    if (!targetChip) continue;
+		    if (!targetChip->cells) continue;
+		    if (!targetChip->cells->n) continue;
+		  
+		    pmCell *targetCell = targetChip->cells->data[0];
+	  	    if (!targetCell) continue;
+		    if (!targetCell->readouts) continue;
+		    if (!targetCell->readouts->n) continue;
+		    pmReadout *targetReadout = targetCell->readouts->data[0];
+		    if (!targetReadout) continue;
+		
+		    pmAstromObj *crosstalk = pmAstromObjAlloc();
+		
+		    crosstalk->Mag = cal->Mag;
+		    crosstalk->chip->x = x_t_chip;
+		    crosstalk->chip->y = y_t_chip;
+		
+		    psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS.SPIKES");
+		    if (crosstalks == NULL) {
+		      crosstalks = psArrayAllocEmpty(100);
+		      if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS.SPIKES", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
+		        psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
+		        goto escape;
+		      }
+		      psFree(crosstalks);
+		    }
+		    psArrayAdd(crosstalks,100,crosstalk);
+		
+		    psFree(targetChipName);
+		    psFree(targetCellName);
+		    psFree(crosstalk);
+	          }
+	        } // End satspike crosstalks
+              } // End calMags
+
+          
+              // We also want to use the refstars to check for crosstalk. In particular, the detections 
+              // do not do well for bright stars, and saturated detections will underestimate the size of the crostalk
+              // Get the array of reference stars we're concerned with.
+              psArray *refstars = psMetadataLookupPtr (&status, readout->analysis, "PSASTRO.REFSTARS");
+              if (refstars == NULL) { return(true); }
+
+              // Check each reference star
+              for (int i = 0; i < refstars->n; i++) {
+	        // This is the source of the ct.
+                pmAstromObj *ref = refstars->data[i];
+
+                if (ref->Mag > CROSS_MAX_MAG) { continue; }
+
+                // Identify which cell holds the star
+                pmChip *CTsourceChip = refChip;
+                pmCell *CTsourceCell = pmCellInChip(refChip,ref->chip->x,ref->chip->y);
+
+                if (!CTsourceCell) { continue; }
+
+                psTrace ("psastro.crosstalk",2,"REF: %d %f (%f %f) %f %f :: %f %f\n",
+                       i,ref->Mag, ref->sky->r,ref->sky->d, ref->FP->x,ref->FP->y, ref->chip->x,ref->chip->y);
+
+                const char *cellName = psMetadataLookupStr(NULL,CTsourceCell->concepts, "CELL.NAME");
+                int U = cellName[2] - '0';
+                int V = cellName[3] - '0';
+                int cellNum = (U*10)+V ;
+
+                float x_cell,y_cell;
+                float x_t_cell,y_t_cell;
+
+                float x_t_chip,y_t_chip;
+	        // int faint_ct = 0; NOTE: not currently used
+                pmCellCoordsForChip(&x_cell,&y_cell,CTsourceCell,ref->chip->x,ref->chip->y);
+
+                x_t_cell = x_cell;
+                y_t_cell = y_cell;
+
+                if (! (U == crossCell) ) {
+                  psTrace ("psastro.crosstalk",2,"Cell (%d%d) on chip (%d%d) not a known crosstalk source.",U,V,X,Y);
+                  continue;
+                }
+
+                int chipTarget = chipNum + crossChipOffset ; 
+                int cellTarget = cellNum + crossCellOffset ; 
+
+                // Convert target cell coordinates to target chip coordinates
+                psString targetChipName = NULL;
+                if(chipTarget > 8) {
+                  psStringAppend(&targetChipName,"XY%2d",chipTarget);
+                }
+                if(chipTarget < 8) {
+                  psStringAppend(&targetChipName,"XY0%1d",chipTarget);
+                }
+                psString targetCellName = NULL;
+                if(cellTarget > 8) {
+                  psStringAppend(&targetCellName,"xy%2d",cellTarget);
+                }
+                if(cellTarget < 8) {
+                  psStringAppend(&targetCellName,"xy0%1d",cellTarget);
+                }
+
+                psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%2dxy%2d@%f,%f [%s %s]",
+                       X,Y,U,V,x_cell,y_cell,chipTarget,cellTarget,x_t_cell,y_t_cell,
+                       targetChipName,targetCellName);
+
+                pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
+                if (!CTtargetCell) continue;
+
+                pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
+
+                psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%2dxy%2d@%f,%f ChipLoc: (%f,%f)",
+                       X,Y,U,V,x_cell,y_cell,chipTarget,cellTarget,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
+                psLogMsg ("psastro", PS_LOG_INFO, "MAXREF2:OTA%d%dxy%d%d@%f,%f CTtarget OTA%2dxy%2d@%f,%f ChipLoc: (%f,%f)",
+                       X,Y,U,V,x_cell,y_cell,chipTarget,cellTarget,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
+
+                // Hunt down the readout for the target, and save the chip position and magnitude of source star.
+                pmChip *targetChip = getChipByName(fpa,targetChipName);
+                if (!targetChip) continue;
+                if (!targetChip->cells) continue;
+                if (!targetChip->cells->n) continue;
+
+                pmCell *targetCell = targetChip->cells->data[0];
+                if (!targetCell) continue;
+                if (!targetCell->readouts) continue;
+                if (!targetCell->readouts->n) continue;
+                pmReadout *targetReadout = targetCell->readouts->data[0];
+                if (!targetReadout) continue;
+
+                //check if the crosstalk is above the target chip background level
+                pmDetEff *tarde = psMetadataLookupPtr(NULL, targetReadout->analysis, PM_DETEFF_ANALYSIS); // Detection efficiency
+                if (isnan(tarde->magRef)) { continue; }
+
+                float TARGET_CROSS_MAX_MAG = tarde->magRef-crossMagOff + MagOffset;
+                if (ref->Mag > TARGET_CROSS_MAX_MAG) { continue; }
+
+                psLogMsg ("psastro", PS_LOG_INFO, "CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%2dxy%2d@%f,%f ChipLoc: (%f,%f) %f",
+                       X,Y,U,V,ref->chip->x,ref->chip->y,chipTarget,cellTarget,x_t_cell,y_t_cell,x_t_chip,y_t_chip,ref->Mag);
+
+                pmAstromObj *crosstalk = pmAstromObjAlloc();
+	    
+                crosstalk->Mag = ref->Mag - MagOffset;
+                crosstalk->chip->x = x_t_chip;
+                crosstalk->chip->y = y_t_chip;
+
+                psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS");
+                if (crosstalks == NULL) {
+                  crosstalks = psArrayAllocEmpty(100);
+                  if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
+                    psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
+                    goto escape;
+                  }
+                  psFree(crosstalks);
+                }
+                psArrayAdd(crosstalks,100,crosstalk);
+	    
+                psFree(targetChipName);
+                psFree(targetCellName);
+                psFree(crosstalk);
+
+	        // Determine if we need to add a spike mask.
+                // TdB20210304: This should not be relevant for faint crosstalk rules. Do this rather ad hoc right now by placing a limit at 8 mags of difference
+                if( crossMagOff > 8.) { continue; }
+	        if (ref->Mag < SPIKE_MAX_MAG) {	      
+	          int Xt = X;
+	          int Yt = Y;
+	          int Vt = V;
 	      
-	      for (Ut = 0; Ut < 8; Ut++) {
-
-		psString targetChipName = NULL;
-		psStringAppend(&targetChipName,"XY%d%d",Xt,Yt);
-		psString targetCellName = NULL;
-		psStringAppend(&targetCellName,"xy%d%d",Ut,Vt);
-		
-		psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f [%s %s]",
-			 X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,
-			 targetChipName,targetCellName);
-/* 		psWarning ("CT bleed ct @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f [%s %s]", */
-/* 			 X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell, */
-/* 			 targetChipName,targetCellName); */
-		
-		pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
-		if (!CTtargetCell) continue;
-		
-		pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
-
-		psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f ChipLoc: (%f,%f)",
-			 X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
-		
-		// Hunt down the readout for the target, and save the chip position and magnitude of source star.
-		pmChip *targetChip = getChipByName(fpa,targetChipName);
-		if (!targetChip) continue;
-		if (!targetChip->cells) continue;
-		if (!targetChip->cells->n) continue;
-		
-		pmCell *targetCell = targetChip->cells->data[0];
-		if (!targetCell) continue;
-		if (!targetCell->readouts) continue;
-		if (!targetCell->readouts->n) continue;
-		pmReadout *targetReadout = targetCell->readouts->data[0];
-		if (!targetReadout) continue;
-		
-		pmAstromObj *crosstalk = pmAstromObjAlloc();
-		
-		crosstalk->Mag = ref->Mag;
-		crosstalk->chip->x = x_t_chip;
-		crosstalk->chip->y = y_t_chip;
-		
-		psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS.SPIKES");
-		if (crosstalks == NULL) {
-		  crosstalks = psArrayAllocEmpty(100);
-		  if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS.SPIKES", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
-		    psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
-		    goto escape;
-		  }
-		  psFree(crosstalks);
-		}
-		psArrayAdd(crosstalks,100,crosstalk);
-		
-		psFree(targetChipName);
-		psFree(targetCellName);
-		psFree(crosstalk);
-	      }
-	    } // End satspike crosstalks
-
-	    
-          } // refstars
+	          for (int Ut = 0; Ut < 8; Ut++) {
+		    psString targetChipName = NULL;
+		    psStringAppend(&targetChipName,"XY%d%d",Xt,Yt);
+		    psString targetCellName = NULL;
+		    psStringAppend(&targetCellName,"xy%d%d",Ut,Vt);
+		
+		    psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f [%s %s]",
+			   X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,
+			   targetChipName,targetCellName);
+		
+		    pmCell *CTtargetCell = getCellByName (CTsourceChip,targetCellName);
+		    if (!CTtargetCell) continue;
+		
+		    pmChipCoordsForCell(&x_t_chip,&y_t_chip,CTtargetCell,x_t_cell,y_t_cell);
+
+		    psTrace ("psastro.crosstalk",2,"CTsource @ OTA%d%dxy%d%d@%f,%f CTtarget OTA%d%dxy%d%d@%f,%f ChipLoc: (%f,%f)",
+		  	   X,Y,U,V,x_cell,y_cell,Xt,Yt,Ut,Vt,x_t_cell,y_t_cell,x_t_chip,y_t_chip);
+		
+		    // Hunt down the readout for the target, and save the chip position and magnitude of source star.
+		    pmChip *targetChip = getChipByName(fpa,targetChipName);
+		    if (!targetChip) continue;
+		    if (!targetChip->cells) continue;
+		    if (!targetChip->cells->n) continue;
+		  
+		    pmCell *targetCell = targetChip->cells->data[0];
+	  	    if (!targetCell) continue;
+		    if (!targetCell->readouts) continue;
+		    if (!targetCell->readouts->n) continue;
+		    pmReadout *targetReadout = targetCell->readouts->data[0];
+		    if (!targetReadout) continue;
+		
+		    pmAstromObj *crosstalk = pmAstromObjAlloc();
+		
+		    crosstalk->Mag = ref->Mag - MagOffset;
+		    crosstalk->chip->x = x_t_chip;
+		    crosstalk->chip->y = y_t_chip;
+		
+		    psArray *crosstalks = psMetadataLookupPtr (&status, targetReadout->analysis, "PSASTRO.CROSSTALKS.SPIKES");
+		    if (crosstalks == NULL) {
+		      crosstalks = psArrayAllocEmpty(100);
+		      if (!psMetadataAdd(targetReadout->analysis,PS_LIST_TAIL,"PSASTRO.CROSSTALKS.SPIKES", PS_DATA_ARRAY, "crosstalk locations", crosstalks)) {
+		        psError(PSASTRO_ERR_CONFIG, false, "failure to add crosstalks to readout");
+		        goto escape;
+		      }
+		      psFree(crosstalks);
+		    }
+		    psArrayAdd(crosstalks,100,crosstalk);
+		
+		    psFree(targetChipName);
+		    psFree(targetCellName);
+		    psFree(crosstalk);
+	          }
+	        } // End satspike crosstalks
+              } // End refMags
+
+            }
+          }
+
+
         } // readout
       } // cell
