Index: /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/Makefile
===================================================================
--- /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/Makefile	(revision 38686)
+++ /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/Makefile	(revision 38687)
@@ -6,4 +6,5 @@
 HOME 	=	$(ROOT)/src/libdvo
 AUTO	=	$(ROOT)/src/libautocode
+BIN	=	$(HOME)/bin
 LIB	= 	$(HOME)/lib
 SRC	=	$(HOME)/src
@@ -22,5 +23,15 @@
 FULL_LDFLAGS  = $(BASE_LDFLAGS) -lFITS -lohana
 
-default: install
+TEST_CFLAGS   =	$(BASE_CFLAGS)
+TEST_CPPFLAGS =	$(BASE_CPPFLAGS)
+TEST_LDFLAGS  = $(BASE_LDFLAGS) -ldvo -lFITS -lohana -ltap_ohana
+
+TESTPROG = tap_AstromOffsetMapIO
+$(TESTPROG) : % : $(TESTBIN)/%
+test: $(TESTPROG)
+	for i in $(TESTPROG); do $(TESTBIN)/$$i 2>&1 | $(TESTHARNESS); done
+test.verbose: $(TESTPROG)
+	for i in $(TESTPROG); do $(TESTBIN)/$$i 2>&1 |& $(TESTHARNESS) -v; done
+
 install: $(DESTLIB)/libdvo.a $(DESTLIB)/libdvo.$(DLLTYPE)
 libdvo: $(LIB)/libdvo.$(ARCH).a $(LIB)/libdvo.$(ARCH).$(DLLTYPE)
@@ -183,10 +194,3 @@
 	cd $(AUTO) && $(MAKE) clean
 
-TESTPROG = 
-$(TESTPROG) : % : $(TESTBIN)/% $(OBJS)
-test: $(TESTPROG)
-	for i in $(TESTPROG); do $(TESTBIN)/$$i 2>&1 | $(TESTHARNESS); done
-test.verbose: $(TESTPROG)
-	for i in $(TESTPROG); do $(TESTBIN)/$$i 2>&1 |& $(TESTHARNESS) -v; done
-
-.PRECIOUS: $(ASRC)/%.c
+# .PRECIOUS: $(ASRC)/%.c
Index: /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/include/libdvo_astro.h
===================================================================
--- /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/include/libdvo_astro.h	(revision 38686)
+++ /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/include/libdvo_astro.h	(revision 38687)
@@ -160,8 +160,10 @@
 
 /* in AstromOffsetMapIO.c */
-AstromOffsetTable *AstromOffsetMapLoad (char *filename, int VERBOSE);
+AstromOffsetTable *AstromOffsetMapLoad (char *filename, int Nrows, int VERBOSE);
 int AstromOffsetMapSave (AstromOffsetTable *table, char *filename);
 AstromOffsetTable *AstromOffsetMapToTable(AstromOffsetMap_Disk_6x6 *map_disk, off_t Nmap);
 AstromOffsetMap_Disk_6x6 *AstromOffsetTableToMap(AstromOffsetTable *table, off_t *Nmap);
+int AstromOffsetTableSetIDs (AstromOffsetTable *table);
+AstromOffsetTable *AstromOffsetMapAppendToTable(AstromOffsetTable *table, AstromOffsetMap_Disk_6x6 *map_disk, off_t Nmap);
 
 /* in AstromOffsetMapOps.c */
Index: /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/src/AstromOffsetMapIO.c
===================================================================
--- /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/src/AstromOffsetMapIO.c	(revision 38686)
+++ /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/src/AstromOffsetMapIO.c	(revision 38687)
@@ -1,5 +1,5 @@
 # include "dvo.h"
 
-AstromOffsetTable *AstromOffsetMapLoad (char *filename, int VERBOSE) {
+AstromOffsetTable *AstromOffsetMapLoad (char *filename, int Nrows, int VERBOSE) {
 
   off_t Nmap;
@@ -7,6 +7,8 @@
   Header header;
   Matrix matrix;
+
   Header theader;
   FTable ftable;
+  ftable.header = &theader;
 
   FILE *f = fopen (filename, "r");
@@ -17,5 +19,4 @@
 
   /* load in table data */
-  ftable.header = &theader;
   if (!gfits_fread_header (f, &header)) {
     if (VERBOSE) fprintf (stderr, "can't read Astrom Offset Map header\n");
@@ -30,26 +31,52 @@
   }
 
-  // for now, we only have one flavor (6x6)
-
-  if (!gfits_fread_ftable (f, &ftable, "ASTROM_OFFSET_MAP_DISK_6x6")) {
-    if (VERBOSE) fprintf (stderr, "can't read Astrom Offset Map table\n");
-    gfits_free_header (&header);
-    gfits_free_matrix (&matrix);
-    fclose (f);
-    return (NULL);
-  }
-  AstromOffsetMap_Disk_6x6 *map_disk = gfits_table_get_AstromOffsetMap_Disk_6x6 (&ftable, &Nmap, NULL, NULL);
-  if (!map_disk) {
-    fprintf (stderr, "ERROR: failed to read Astrom Offset Map\n");
-    exit (2);
-  }
-
-  // AstromOffsetMap_Disk_6x6 *map_disk is an external format stored as an array of maps.
-  // Convert the disk array of maps to then internal format in a rich structure:
-  AstromOffsetTable *table = AstromOffsetMapToTable (map_disk, Nmap);
+  // the output table is not what is stored in the FITS file.  read and convert 
+  // from the disk file format
+  AstromOffsetTable *table = NULL;
+
+  // for now, we only have one flavor (6x6) of disk file format
+
+  // loop over the ftable reading blocks of 100k rows at a time
+  if (Nrows) {
+    if (!gfits_find_Xheader (f, ftable.header, "ASTROM_OFFSET_MAP_DISK_6x6")) myAbort ("problem 1");
+    int NrowsTotal = ftable.header[0].Naxis[1];
+    int Nblocks = (NrowsTotal % Nrows) ? (int) (NrowsTotal / Nrows) + 1 : (NrowsTotal / Nrows);
+
+    int i;
+    for (i = 0; i < Nblocks; i++) {
+      if (!gfits_fread_ftable_range (f, FALSE, &ftable, i*Nrows, Nrows)) myAbort ("problem 2");
+    
+      AstromOffsetMap_Disk_6x6 *map_disk = gfits_table_get_AstromOffsetMap_Disk_6x6 (&ftable, &Nmap, NULL, NULL);
+      if (!map_disk) myAbort ("ERROR: failed to read Astrom Offset Map\n");
+
+      table = AstromOffsetMapAppendToTable (table, map_disk, Nmap);
+      gfits_free_table  (&ftable);
+    }
+    AstromOffsetTableSetIDs (table);
+    gfits_free_header (ftable.header);
+  } else {
+
+    // convert the blocks into the equivalent table entries and append
+    if (!gfits_fread_ftable (f, &ftable, "ASTROM_OFFSET_MAP_DISK_6x6")) {
+      if (VERBOSE) fprintf (stderr, "can't read Astrom Offset Map table\n");
+      gfits_free_header (&header);
+      gfits_free_matrix (&matrix);
+      fclose (f);
+      return (NULL);
+    }
+    AstromOffsetMap_Disk_6x6 *map_disk = gfits_table_get_AstromOffsetMap_Disk_6x6 (&ftable, &Nmap, NULL, NULL);
+    if (!map_disk) {
+      fprintf (stderr, "ERROR: failed to read Astrom Offset Map\n");
+      exit (2);
+    }
+
+    // AstromOffsetMap_Disk_6x6 *map_disk is an external format stored as an array of maps.
+    // Convert the disk array of maps to then internal format in a rich structure:
+    table = AstromOffsetMapToTable (map_disk, Nmap);
+    gfits_free_table  (&ftable);
+  }
 
   gfits_free_header (&theader);
   gfits_free_matrix (&matrix);
-  gfits_free_table  (&ftable);
 
   return (table);
@@ -139,6 +166,6 @@
     
     // STORE THESE VALUES?
-    table->map[i][0].dY 	  = map_disk[i].dX;
-    table->map[i][0].dX 	  = map_disk[i].dY;
+    table->map[i][0].dX 	  = map_disk[i].dX;
+    table->map[i][0].dY 	  = map_disk[i].dY;
 
     // since this was on disk, we obviously keep it
@@ -182,6 +209,4 @@
     map_disk[Ndisk].dY 	    = table->map[i][0].dY;
 
-    
-
     for (j = 0; j < map_disk[Ndisk].Nx; j++) {
       for (k = 0; k < map_disk[Ndisk].Ny; k++) {
@@ -206,2 +231,79 @@
 }
 
+AstromOffsetTable *AstromOffsetMapAppendToTable(AstromOffsetTable *table, AstromOffsetMap_Disk_6x6 *map_disk, off_t Nmap) {
+
+  int i, j, k, Nstart;
+
+  if (table == NULL) {
+    ALLOCATE (table, AstromOffsetTable, 1);
+    Nstart = 0;
+    table->Nmap = Nmap;
+    ALLOCATE (table->map, AstromOffsetMap *, Nmap);
+  } else {
+    Nstart = table->Nmap;
+    table->Nmap += Nmap;
+    REALLOCATE (table->map, AstromOffsetMap *, table->Nmap);
+  }
+
+  // append map values (this allocates just the area needed for each image, not the
+  // full 6x6, saving some memory while doing the analysis)
+  for (i = 0; i < Nmap; i++) {
+    int N = i + Nstart;
+    ALLOCATE (table->map[N], AstromOffsetMap, 1);
+
+    table->map[N][0].Nx 	  = map_disk[i].Nx;
+    table->map[N][0].Ny 	  = map_disk[i].Ny;
+    table->map[N][0].tableID 	  = map_disk[i].tableID;
+    table->map[N][0].imageID 	  = map_disk[i].imageID;
+    
+    // STORE THESE VALUES?
+    table->map[N][0].dX 	  = map_disk[i].dX;
+    table->map[N][0].dY 	  = map_disk[i].dY;
+
+    // since this was on disk, we obviously keep it
+    table->map[N][0].keep 	  = TRUE;
+
+    ALLOCATE (table->map[N][0].dXv, float *, map_disk[i].Nx);
+    ALLOCATE (table->map[N][0].dYv, float *, map_disk[i].Nx);
+
+    for (j = 0; j < map_disk[i].Nx; j++) {
+      ALLOCATE (table->map[N][0].dXv[j], float, map_disk[i].Ny);
+      ALLOCATE (table->map[N][0].dYv[j], float, map_disk[i].Ny);
+
+      for (k = 0; k < map_disk[i].Ny; k++) {
+	table->map[N][0].dXv[j][k] = map_disk[i].dXv[j][k];
+	table->map[N][0].dYv[j][k] = map_disk[i].dYv[j][k];
+      }
+    }
+  }
+  return table;
+}
+
+int AstromOffsetTableSetIDs (AstromOffsetTable *table) {
+
+  int i;
+
+  // find the max value of imageID
+  int MaxTableID = 0;
+  int MaxImageID = 0;
+  for (i = 0; i < table->Nmap; i++) {
+    MaxTableID = MAX(table->map[i][0].tableID, MaxTableID);
+    MaxImageID = MAX(table->map[i][0].imageID, MaxImageID);
+  }
+  table->MaxTableID = MaxTableID;
+  table->MaxImageID = MaxImageID;
+
+  // generate the index and init values to -1
+  ALLOCATE (table->imageIDtoTableSeq, int, MaxImageID + 1);
+  for (i = 0; i <= MaxImageID; i++) {
+    table->imageIDtoTableSeq[i] = -1;
+  }
+
+  // assign the ID values
+  for (i = 0; i < table->Nmap; i++) {
+    int ImageID = table->map[i][0].imageID;
+    myAssert (table->imageIDtoTableSeq[ImageID] == -1, "oops, duplicate image IDs");
+    table->imageIDtoTableSeq[ImageID] = i;
+  }
+  return TRUE;
+}
Index: /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/src/LoadImages.c
===================================================================
--- /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/src/LoadImages.c	(revision 38686)
+++ /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/src/LoadImages.c	(revision 38687)
@@ -85,5 +85,5 @@
 
   if (table) AstromOffsetTableFree(table);
-  table = AstromOffsetMapLoad (mapfile, FALSE);
+  table = AstromOffsetMapLoad (mapfile, 100000, FALSE);
 
   // assign images.coords.offsetMap -> table->map[i]
Index: /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/test/tap_AstromOffsetMapIO.c
===================================================================
--- /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/test/tap_AstromOffsetMapIO.c	(revision 38687)
+++ /branches/eam_branches/ipp-20150625/Ohana/src/libdvo/test/tap_AstromOffsetMapIO.c	(revision 38687)
@@ -0,0 +1,95 @@
+# include "dvo.h"
+# include "tap_ohana.h"
+
+int compare_tables (AstromOffsetTable *table_src, AstromOffsetTable *table_tgt);
+
+int main (void) {
+
+  int i, j, k, status;
+
+  plan_tests (181);
+
+  diag ("libdvo AstromOffsetMapIO.c tests");
+
+  /*** create a small, simple reference AstroMap ***/
+  AstromOffsetTable *table = NULL;
+  ALLOCATE (table, AstromOffsetTable, 1);
+
+  table->Nmap = 4;
+  ALLOCATE (table->map, AstromOffsetMap *, table->Nmap);
+
+  // assign the map values (this allocates just the area needed for each image, not the
+  // full 6x6, saving some memory while doing the analysis)
+  for (i = 0; i < table->Nmap; i++) {
+    ALLOCATE (table->map[i], AstromOffsetMap, 1);
+
+    table->map[i][0].Nx 	  = i + 1;
+    table->map[i][0].Ny 	  = i + 1;
+    table->map[i][0].tableID      = i + 10;
+    table->map[i][0].imageID      = i + 20;
+    
+    // STORE THESE VALUES?
+    table->map[i][0].dX 	  = 2*i + 0.5;
+    table->map[i][0].dY 	  = 3*i + 0.5;
+
+    // since this was on disk, we obviously keep it
+    table->map[i][0].keep 	  = TRUE;
+
+    ALLOCATE (table->map[i][0].dXv, float *, table->map[i][0].Nx);
+    ALLOCATE (table->map[i][0].dYv, float *, table->map[i][0].Nx);
+
+    for (j = 0; j < table->map[i][0].Nx; j++) {
+      ALLOCATE (table->map[i][0].dXv[j], float, table->map[i][0].Ny);
+      ALLOCATE (table->map[i][0].dYv[j], float, table->map[i][0].Ny);
+
+      for (k = 0; k < table->map[i][0].Ny; k++) {
+	table->map[i][0].dXv[j][k] = i+j+k+1;
+	table->map[i][0].dYv[j][k] = i+j+k+2;
+      }
+    }
+  }
+
+  status = AstromOffsetMapSave (table, "test.v0.fits");
+  ok (status, "wrote test table to file");
+
+  AstromOffsetTable *table_full = AstromOffsetMapLoad ("test.v0.fits", 0, TRUE);
+  ok (table_full, "read test table from file");
+
+  /*** compare table_full and table above ***/
+  diag ("compare table_full and table");
+  compare_tables (table_full, table);
+
+  /*** compare AstromOffsetMapLoad in blocks vs single read ***/
+  AstromOffsetTable *table_rows = AstromOffsetMapLoad ("test.v0.fits", 100, TRUE);
+  ok (table_rows, "read in table in 100 rows per read");
+    
+  diag ("compare table_rows and table");
+  compare_tables (table_rows, table);
+    
+  return exit_status();
+}
+
+int compare_tables (AstromOffsetTable *table_src, AstromOffsetTable *table_tgt) {
+
+  int i, j, k;
+
+  ok (table_tgt->Nmap == table_src->Nmap, "number of maps matches");
+    
+  for (i = 0; i < table_src->Nmap; i++) {
+    ok (table_tgt->map[i][0].Nx      == table_src->map[i][0].Nx, 	"Nx sizes match");
+    ok (table_tgt->map[i][0].Ny      == table_src->map[i][0].Ny, 	"Ny sizes match");
+    ok (table_tgt->map[i][0].tableID == table_src->map[i][0].tableID, "tableIDs match");
+    ok (table_tgt->map[i][0].imageID == table_src->map[i][0].imageID, "imageIDs match");
+    ok (table_tgt->map[i][0].dX      == table_src->map[i][0].dX,      "dX matches");
+    ok (table_tgt->map[i][0].dY      == table_src->map[i][0].dY,      "dY matches");
+    ok (table_tgt->map[i][0].keep    == table_src->map[i][0].keep,    "keep matches");
+
+    for (j = 0; j < table_src->map[i][0].Nx; j++) {
+      for (k = 0; k < table_src->map[i][0].Ny; k++) {
+	ok (table_tgt->map[i][0].dXv[j][k] == table_src->map[i][0].dXv[j][k], "dX values match");
+	ok (table_tgt->map[i][0].dYv[j][k] == table_src->map[i][0].dYv[j][k], "dY values match"); 
+      }
+    }
+  }
+  return TRUE;
+}
