1,523c1,468
< // FssimApp.cpp : Implementation of the central class of the Fssim Application
< 
< #include <string>
< #include <list>
< #include <vector>
< #include <iostream>
< #include <iomanip>
< 
< #include "FssimApp.h"
< 
< #include "Serializer.h"
< #include "Data.h"
< #include "Block.h"
< #include "Zone.h"
< #include "Au.h"
< #include "AxsDef.h"
< #include "Group.h"
< #include "TimberClass.h"
< #include "Table.h"
< 
< #include "InvalidDataException.h"
< 
< #include "init.h"
< 
< using namespace std;
< using namespace tsb;
< 
< #ifdef _TSB_MAIN_DEBUG
< namespace tsb
< {
<     void debug_tests()
<     {
<     	/*
<     	static int count = 0;
<         int testData = 111111;
<     	printf("c sucks");
<     	//printf("debug test #: %d", count);
<     	cout << "debug test #: " << count << endl;
< 
<         string m_fileName = "/home/kbelange/fssim_code/C++_v3.0/data/hubert/FssimDump";
<         char buffer[10];
<         sprintf(buffer, "%d.bin", count);
<         m_fileName += buffer;
<         //fstream fileStream( m_fileName.c_str(), ios::out|ios::binary );
<         try
<         {
<             File file(m_fileName);
<             file.Open();
<             Archive database(&file);
<             database.write( &testData, sizeof(testData) ); // data, size
< 
<             int inputTest = 0;
<             database.read( &inputTest, sizeof(inputTest) ); // data, size
<             //printf("test data: %d", inputTest);
< 
<             cout << "test data: " << inputTest << endl;
<     	}
<         catch(exception& e)
<         {
<         	printf("output file stream exception: %s", e.what());
<         }
<                 if (fileStream.is_open())
<                 {
<                 	cout << "filestream is open" << endl;
<                 	fileStream << "filestream is open from fssim!: " << count++ << endl;
<                 }
<                 else
<                 {
<                 	cout << "filestream is NOT open" << endl;
<                 }
< */
<     	return;
<     }
< } // end namespace tsb;
< #endif
< 
< // initialize static pointer to application object, set in constructor
< FssimApp* FssimApp::m_pApplication = 0;
< 
< // initialize constant static data
< const char* FssimApp::m_kNullString = "n/a";
< const string FssimApp::m_kOutputDirectory = "reports";
< const double FssimApp::m_kRoundError = 0.001;
< const double FssimApp::m_kMaxFloat = 1000000000000.0;
< 
< void FssimApp::display_version()
< {
<     printf("\n\nFSSIM v4.0.4");
<     printf("\n(c) 1994-2001, British Columbia Ministry of Forests");
<     printf("\nThis version: 26. July, 2001\n\n");
< }
< 
< void FssimApp::display_usage(const string& programName)
< {
< 	printf( "\n\nUsage: %s [-u | -b] <DataDirectory>\n\n", programName.c_str() );
< 	cout << setw(20) << "first run)"
< 	     << " use -u to read \".dat\" files"
<          << endl << setw(20) << "subsequent runs)"
<          << " use -b to restore state from binary file (faster)" << endl
<          << endl << setw(4) << " "
<          << "Re-run using -u after any modifications to the following files:"
<          << endl << endl << setw(8) << " "
<          << "adjacency.dat, axs.dat, class.dat, group.dat, landoaf.dat, "
<          << endl << setw(8) << " " << "neighbours.dat, oaf.dat, regen.dat, road.dat, transfer.dat, and vols.dat"
<          << endl << endl << setw(4) << " "
<          << "Re-run using -u after changing \"Randomizer\" options in config.dat" << endl;
< 
<     string message = "Invalid usage - program exiting...";
< 	throw(message); // TO-DO: throw exception
< }
< 
< FssimApp::FssimApp(const string& dataPath, const string& binaryFileName, bool updateBinary)
<     : m_zoneList(0), m_tableList(0),
<       m_candidateList(0), m_groupList(0), m_blockList(0),
<       m_planHorizon(0), m_harvestRule(RELATIVE_OLDEST_FIRST),
<       m_enableRandomization(false), m_enableClassSplit(true),
<       m_enableReports(true), m_enableReportHeaders(true),
<       m_enableTrace(false), m_enableBlockReport(false),
<       m_transfersSpecified(false), m_applyFactor(true),
<       m_minSplitThreshold(0.0), m_ageOffset(0), m_outputDirectory(m_kOutputDirectory),
<       m_lastZoneID(0), m_lastGroupID(0), m_lastTableID(0),
<       // needed to fake model into creating m_zone0->priority[]
<       m_dataPath(dataPath), m_binaryFileName(binaryFileName),
<       m_updateBinary(updateBinary),
<       m_start(0), m_finish(0)//, m_duration(0.0)
< {
<     FssimApp::m_pApplication = this;
< 
<     for(int i = 0 ; i < MAX_PLAN_HORIZON ; ++i)
<     {
<         m_periodLength[i] = 0;
<     }
< }
< 
< FssimApp::~FssimApp()
< {
<     this->cleanup_memory();
< }
< 
< void FssimApp::remove_null_classes()
< {
<     ZONE	*zone;
<     AU	*au;
<     TIMBER_CLASS	*timber_class;
< 
<     m_zoneList = (LIST_PTR *)List::reset(m_zoneList);
<     zone = (ZONE *)List::next(m_zoneList);
<     while (zone!= 0)
<     {
<         zone->aulist = (LIST_PTR *)List::reset(zone->aulist);
<         au = static_cast<AU*>(List::next(zone->aulist));
<         while (au != 0)
<         {
<             au->classlist = (LIST_PTR *)List::reset(au->classlist);
<             timber_class = (TIMBER_CLASS *)List::next(au->classlist);
<             while (timber_class != 0)
<             {
<                 if ((timber_class->class_type==FssimApp::INACTIVE)||(timber_class->area<=FssimApp::m_kRoundError))
<                 {
<                     au->classlist = (LIST_PTR *)List::remove(au->classlist, timber_class);
<                     init_delete_class(timber_class);
<                 }
<                 if (au->classlist!= 0)
<                 {
<                     if (au->classlist->size==0)
<                     {
<                         List::done(au->classlist);
<                         au->classlist = 0;
<                     }
<                 }
<                 timber_class = (TIMBER_CLASS *)List::next(au->classlist);
<             }
<             au = static_cast<AU*>(List::next(zone->aulist));
<         }
<         zone = (ZONE *)List::next(m_zoneList);
<     }
< }
< // either read data from text files and output binary dump file
< // or read input from previous binary dump file
< void FssimApp::readData()
< {
<     Data dataFileObject(m_dataPath);
< 
<     if (m_updateBinary) // read data from text files and output binary dump file
<     {
<         // initialization moved to FssimApp::FssimApp constructor
< 
<         // prepare to write (serialize) binary data to file
<         bool writing = true;
<         Serializer binaryWriter(m_dataPath, m_binaryFileName, writing);
<         binaryWriter.open();
<         binaryWriter.clear(); // empty any previous binary data from file
< 
<         // configs are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_config", &Data::read_config, dataFileObject);
< 
<         // serialize m_enableRandomization flag; throws exception on read if doesn't match binary file
<         int randFlag = static_cast<int>(m_enableRandomization);
<         binaryWriter.write( &(randFlag), sizeof(randFlag) );
< 
<         // time parameters are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_time_parameters", &Data::read_time_parameters, dataFileObject);
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         Data::processDataFile("Data::read_table", &Data::read_table, dataFileObject);
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         Data::processDataFile("Data::read_oaf", &Data::read_oaf, dataFileObject);
< 
<         Data::processDataFile("Data::interpolate_tables", &Data::interpolate_tables, dataFileObject);
<         Data::processDataFile("Data::implement_table_oafs", &Data::implement_table_oafs, dataFileObject);
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         Data::processDataFile("Data::read_class", &Data::read_class, dataFileObject);
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         Data::processDataFile("Data::read_group", &Data::read_group, dataFileObject);
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         Data::processDataFile("Data::read_axs", &Data::read_axs, dataFileObject);
< 
<         // targets are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_target", &Data::read_target, dataFileObject);
<         Data::processDataFile("Data::check_targets", &Data::check_targets, dataFileObject);
< 
<         Data::processDataFile("Data::read_regen", &Data::read_regen, dataFileObject);
<         Data::processDataFile("Data::check_regen", &Data::check_regen, dataFileObject);
< 
<         Data::processDataFile("Data::read_landoaf", &Data::read_landoaf, dataFileObject);
<         Data::processDataFile("Data::implement_landoaf", &Data::implement_landoaf, dataFileObject);
< 
<         Data::processDataFile("Data::read_roads", &Data::read_roads, dataFileObject);
< 
<         Data::processDataFile("Data::init_existing_roads", &Data::init_existing_roads, dataFileObject);
< 
<         Data::processDataFile("Data::read_neighbours", &Data::read_neighbours, dataFileObject);
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         cout << endl << "Initialising group eligibility lists..." << endl;
<         tsb::InitGroupEligibilityLists();
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         cout << endl << "Writing tables to binary file..." << endl;
<     	Table::serializeTableList(binaryWriter);
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         cout << endl << "Writing groups to binary file..." << endl;
<     	Group::serializeGroupList(binaryWriter); // also serializes AxsDef members
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         cout << endl << "Writing blocks to binary file..." << endl;
<         Block::serializeBlockList(binaryWriter); // also serializes neighbour Block objects
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         cout << endl << "Writing zones to binary file..." << endl;
<         Zone::serializeZoneList(binaryWriter);
<         // also serializes AxsDef & Au members (including TimberClasses & Regens)
<         // zone serialization needs to be done after Block serialization for Block ID lookup
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         // priorities are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_priorities", &Data::read_priorities, dataFileObject);
< 
<         // transfers are not serialized (they may be manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_transfer", &Data::read_transfer, dataFileObject);
< 
<         // report flags are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_report_flags", &Data::read_report_flags, dataFileObject);
< 
<         //this->writeAll(binaryWriter);
<     }
<     else //read input from previous binary dump file (de-serialize)
<     {
<         // prepare to write (serialize) binary data to file
<         bool writing = false;
<         Serializer binaryReader(m_dataPath, m_binaryFileName, writing);
<         binaryReader.open();
< 
<         // config is not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_config", &Data::read_config, dataFileObject);
< 
<         // serialize m_enableRandomization flag; throws exception on read if doesn't match binary file
<         int randFlag = 0;
<         binaryReader.read( &(randFlag), sizeof(randFlag) );
<         if (m_enableRandomization != static_cast<bool>(randFlag))
<         {
< #ifdef _TSB_RAND_DEBUG
<             cerr << "randFlag:" << randFlag << endl
<                  << "m_enableRandomization: " << m_enableRandomization << endl;
< #endif
<             string invalidValue("Inconsistent Randomization Flag: ");
<             if (randFlag)
<             {
<                 invalidValue += "(first: 'On', now: 'Off')";
<             }
<             else
<             {
<                 invalidValue += "(first: 'Off', now: 'On')";
<             }
<             string message("If you change randomization options in config.dat, you must re-run fssim with the '-u' flag. ");
< 
<             throw InvalidDataException(invalidValue, message);
<         }
< 
<         // time parameters are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_time_parameters", &Data::read_time_parameters, dataFileObject);
< 
<         cout << endl << "Reading tables from binary file..." << endl;
<     	Table::serializeTableList(binaryReader);
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<     	cout << endl << "Reading groups from binary file..." << endl;
<     	Group::serializeGroupList(binaryReader); // also serializes AxsDef members
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         cout << endl << "Reading blocks from binary file..." << endl;
<         Block::serializeBlockList(binaryReader); // also serializes neighbour Block objects
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         cout << endl << "Reading zones from binary file..." << endl;
<         Zone::serializeZoneList(binaryReader);
<         // also serializes AxsDef & Au members (including TimberClasses & Regens)
<         // zone serialization needs to be done after Block serialization for Block ID lookup
< 
< #ifdef _TSB_TIME_DEBUG
<         m_finish = clock();
<         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
< #endif
< 
<         // targets are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_target", &Data::read_target, dataFileObject);
<         Data::processDataFile("Data::check_targets", &Data::check_targets, dataFileObject);
< 
<         // moved from before serialization to after
<         Data::processDataFile("Data::check_regen", &Data::check_regen, dataFileObject);
< 
<         // moved from before serialization to after
<         // priorities are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_priorities", &Data::read_priorities, dataFileObject);
< 
<         Data::processDataFile("Data::read_transfer", &Data::read_transfer, dataFileObject);
< 
<         // report flags are not serialized (they are manipulated by analysts across serial loads)
<         Data::processDataFile("Data::read_report_flags", &Data::read_report_flags, dataFileObject);
< 
<     	binaryReader.close();
<     }
< }
< 
< void FssimApp::deleteBlockList()
< {
<     BLOCK	*block;
<     HASHREC	*hashrec;
< 
<     cout << endl << "Deleting block list..." << endl;
<     m_blockList = (LIST_PTR *)List::reset(m_blockList);
<     hashrec = (HASHREC *)List::next(m_blockList);
<     while (hashrec != 0)
<     {
<         hashrec->candidates = (LIST_PTR *)List::reset(hashrec->candidates);
<         block = (BLOCK *)List::next(hashrec->candidates);
<         while (block != 0)
<         {
<             init_delete_block(block);
<             block = (BLOCK *)List::next(hashrec->candidates);
<         }
<         List::done(hashrec->candidates);
<         hashrec->candidates = 0;
<         hashrec = (HASHREC *)List::next(m_blockList);
<     }
<     List::done(m_blockList);
<     m_blockList = 0;
< 
< }
< 
< void FssimApp::deleteGroupList()
< {
<     GROUP	*group;
< 
<     cout << endl << "Deleting group list..." << endl;
<     //if (0 != m_groupList && 0 != m_groupList->start)
<     //{
<         m_groupList = (LIST_PTR *)List::reset(m_groupList);
<         group = (GROUP *)List::next(m_groupList);
<         while (group != 0)
<         {
<             init_delete_group(group);
<             group = (GROUP *)List::next(m_groupList);
<         }
<         List::done(m_groupList);
<         m_groupList = 0;
<     //}
< }
< 
< void FssimApp::deleteZoneList()
< {
<     ZONE	*zone;
< 
<     cout << endl << "Deleting zone list..." << endl;
<     //if (0 != m_zoneList && 0 != m_zoneList->start)
<     //{
<         m_zoneList = (LIST_PTR *)List::reset(m_zoneList);
<         zone = (ZONE *)List::next(m_zoneList);
<         while (zone != 0)
<         {
<             init_delete_zone(zone);
<             zone = (ZONE *)List::next(m_zoneList);
<         }
< 
<         List::done(m_zoneList);
<         m_zoneList = 0;
<     //}
< }
< 
< void FssimApp::deleteTableList()
< {
<     TABLE	*table;
< 
<     cout << endl << "Deleting table list..." << endl;
<     //if (0 != m_tableList && 0 != m_tableList->start)
<     //{
<         m_tableList = (LIST_PTR *)List::reset(m_tableList);
<         table = (TABLE *)List::next(m_tableList);
<         while (table != 0)
<         {
<             init_delete_table(table);
<             table = (TABLE *)List::next(m_tableList);
<         }
<         List::done(m_tableList);
<         m_tableList = 0;
<     //}
< }
< 
< void FssimApp::cleanup_memory()
< {
<     cout << "\nFreeing memory..." << endl;
< 
<     this->deleteBlockList();
<     this->deleteZoneList();
<     this->deleteTableList();
<     this->deleteGroupList();
< 
<     printf("Done\n");
< }
< 
< void FssimApp::nullOrCopyLabel(char* target, const char* source)
< {
<     //cout << "source: " << source << endl;
<     // strlen doesn't include terminal null
<     if ( 0 != source && FssimApp::MAX_LABEL_LENGTH > strlen(source) )
<     {
<         strcpy(target, source);
<     }
<     else // if null label
<     {
<         for (int i = 0; i < FssimApp::MAX_LABEL_LENGTH ; ++i)
<         {
<             target[i] = '\0';
<         }
<     }
<     //cout << "target: " << target << endl;
< }
---
> // FssimApp.cpp : Implementation of the central class of the Fssim Application
> 
> #include <string>
> #include <list>
> #include <iostream>
> #include <iomanip>
> #include <vector>
> 
> #include "FssimApp.h"
> 
> #include "Candidate.h"
> #include "Serializer.h"
> #include "Data.h"
> #include "Block.h"
> #include "Zone.h"
> #include "Au.h"
> #include "AxsDef.h"
> #include "Group.h"
> #include "TimberClass.h"
> #include "Table.h"
> 
> #include "init.h"
> 
> using namespace std;
> using namespace tsb;
> 
> 
> #ifdef _TSB_DEBUG
> namespace tsb
> {
>     void debug_tests()
>     {
>     	return;
>     }
> } // end namespace tsb;
> #endif
> 
> 
> // initialize static pointer to application object, set in constructor
> FssimApp* FssimApp::m_pApplication = 0;
> 
> void FssimApp::display_version()
> {
>     cout << endl << endl << "FSSIM v4.1b [BETA]" << endl
>          << "(c) 1994-2001, British Columbia Ministry of Forests" << endl
>          << "This version: 09. July, 2001" << endl << endl;
> }
> 
> void FssimApp::display_usage(const string& programName)
> {
> 	cout << endl << endl << "Usage: " << programName.c_str() << " [-u | -b] <DataDirectory>" << endl << endl;
> 	cout << setw(20) << "first run)"
> 	     << " use -u to read \".dat\" files"
>          << endl << setw(20) << "subsequent runs)"
>          << " use -b to restore state from binary file (faster)" << endl
>          << endl << setw(4) << " "
>          << "Re-run using -u after any modifications to the following files:"
>          << endl << endl << setw(8) << " "
>          << "adjacency.dat, axs.dat, class.dat, group.dat, landoaf.dat, "
>          << endl << setw(8) << " " << "neighbours.dat, oaf.dat, regen.dat, road.dat, transfer.dat, and vols.dat"
>          << endl << endl << setw(4) << " "
>          << "Re-run using -u after changing \"Randomizer\" options in config.dat" << endl;
> 
>     string message = "Invalid usage - program exiting...";
> 	throw(message); // TO-DO: throw exception
> }
> 
> FssimApp::FssimApp(const string& dataPath, const string& binaryFileName, bool updateBinary)
>     : m_planHorizon(0), m_harvestRule(RELATIVE_OLDEST_FIRST),
>       m_periodLength( valarray<int>(0, MAX_PLAN_HORIZON + 1) ),
>       m_periodLengthDouble( valarray<double>(0.0, MAX_PLAN_HORIZON + 1) ),
>       m_enableRandomization(false), m_enableClassSplit(true),
>       m_enableReports(true), m_enableReportHeaders(true),
>       m_enableTrace(false), m_enableBlockReport(false),
>       m_transfersSpecified(false), m_applyFactor(true),
>       m_minSplitThreshold(0), m_ageOffset(0),
>       m_outputDirectory(FssimUtil::m_kOutputDirectory),
>       m_zoneCount(0), m_auCount(0), m_groupCount(0),
>       m_tableCount(0), m_blockCount(0),
>       // needed to fake model into creating m_zone0->priority[]
>       m_dataPath(dataPath), m_binaryFileName(binaryFileName),
>       m_updateBinary(updateBinary), m_pDataFileObject(0),
>       m_currentPeriod(0), m_doneHarvest(BEFORE),
>       m_start(0), m_finish(0)
> {
>     FssimApp::m_pApplication = this;
> }
> 
> FssimApp::~FssimApp()
> {
>     this->cleanup_memory();
> }
> 
> void FssimApp::remove_null_classes()
> {
>     typedef vector<ZoneStruct*>::iterator ZI;
> 
> #ifdef _TSB_REMOVE_NULL_CLASSES_DEBUG
>     int zoneCounter = 0;
>     cout << "remove_null_classes: size of zone list = " << m_zoneList.size() << endl;
> #endif
> 
>     for (ZI zoneIter = m_zoneList.begin(); zoneIter != m_zoneList.end(); ++zoneIter)
>     {
>         typedef vector<AUStruct*>::iterator AI;
> 
> #ifdef _TSB_REMOVE_NULL_CLASSES_DEBUG
>         int auCounter = 0;
>         cout << endl << "processing zone # " << ++zoneCounter << endl;
>         cout << "remove_null_classes: size of au list = " << (*zoneIter)->aulist.size() << endl;
> #endif
> 
>         for (AI auIter = (*zoneIter)->aulist.begin(); auIter != (*zoneIter)->aulist.end(); ++auIter)
>         {
>             typedef multimap<int, TimberClassStruct*>::iterator CI;
>             multimap<int, TimberClassStruct*>& timberClassList = (*auIter)->classlist;
> 
> #ifdef _TSB_REMOVE_NULL_CLASSES_DEBUG
>             int classCounter = 0;
>             cout << endl << "processing au # " << ++auCounter << endl;
>             cout << "remove_null_classes: size of (*auIter)->classlist list = " << (*auIter)->classlist.size() << endl;
>             cout << "remove_null_classes: size of timberClassList list = " << timberClassList.size() << endl;
> #endif
> 
>             for (CI classIter = timberClassList.begin(); classIter != timberClassList.end(); ++classIter)
>             {
> 
> #ifdef _TSB_REMOVE_NULL_CLASSES_DEBUG
>                 ++classCounter;
>                 cout << "processing class # " << classCounter << endl;
> #endif
> 
>                 TimberClassStruct* pCurrentTimberClass = classIter->second;
>                 if ((pCurrentTimberClass->class_type == GroupDefStruct::INACTIVE) || (pCurrentTimberClass->area <= FssimUtil::m_kRoundError))
>                 {
> 
> #ifdef _TSB_REMOVE_NULL_CLASSES_DEBUG
>                     cout << "deleting class # " << classCounter << endl;
>                     cout << "new size of timberClassList list = " << timberClassList.size() << endl;
>                     cout << "address of class being deleted: " << pCurrentTimberClass << endl;
> #endif
> 
>                     init_delete_class(pCurrentTimberClass);
>                     pCurrentTimberClass = 0;
> 		            timberClassList.erase(classIter);
>                 }
>             }
>         }
>     }
> }
> 
> // can't be inlined due to reciprocal definition of FssimApp and Data
> int FssimApp::getCurrentLineNumber()
> {
>     if (0 != m_pDataFileObject)
>     {
>         return m_pDataFileObject->getLineNumber();
>     }
>     else
>     {
>         return 0;
>     }
> }
> 
> string FssimApp::getCurrentInputFileName()
> {
>     if (0 != m_pDataFileObject)
>     {
>         return m_pDataFileObject->getFileName();
>     }
>     else
>     {
>         return string("");
>     }
> }
> 
> // either read data from text files and output binary dump file
> // or read input from previous binary dump file
> void FssimApp::readData() throw (IOException)
> {
>     Data dataFileObject(m_dataPath);
>     m_pDataFileObject = &dataFileObject;
> 
>     if (m_updateBinary) // read data from text files and output binary dump file
>     {
>         // prepare to write (serialize) binary data to file
>         bool writing = true;
>         Serializer binaryWriter(m_dataPath, m_binaryFileName, writing);
>         binaryWriter.open();
>         binaryWriter.clear(); // empty any previous binary data from file
> 
>         // configs are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_config", &Data::read_config, dataFileObject);
> 
>         // serialize m_enableRandomization flag; throws exception on read if doesn't match binary file
>         int randFlag = static_cast<int>(m_enableRandomization);
>         binaryWriter.write( &(randFlag), sizeof(randFlag) );
> 
>         // time parameters are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_time_parameters", &Data::read_time_parameters, dataFileObject);
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         Data::processDataFile("Data::read_table", &Data::read_table, dataFileObject);
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         Data::processDataFile("Data::read_oaf", &Data::read_oaf, dataFileObject);
> 
>         Data::processDataFile("Data::interpolate_tables", &Data::interpolate_tables, dataFileObject);
>         Data::processDataFile("Data::implement_table_oafs", &Data::implement_table_oafs, dataFileObject);
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         Data::processDataFile("Data::read_class", &Data::read_class, dataFileObject);
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         Data::processDataFile("Data::read_group", &Data::read_group, dataFileObject);
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         Data::processDataFile("Data::read_axs", &Data::read_axs, dataFileObject);
> 
>         // targets are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_target", &Data::read_target, dataFileObject);
>         Data::processDataFile("Data::check_targets", &Data::check_targets, dataFileObject);
> 
>         Data::processDataFile("Data::read_regen", &Data::read_regen, dataFileObject);
>         Data::processDataFile("Data::check_regen", &Data::check_regen, dataFileObject);
> 
>         Data::processDataFile("Data::read_landoaf", &Data::read_landoaf, dataFileObject);
>         Data::processDataFile("Data::implement_landoaf", &Data::implement_landoaf, dataFileObject);
> 
>         Data::processDataFile("Data::read_roads", &Data::read_roads, dataFileObject);
>         Data::processDataFile("Data::init_existing_roads", &Data::init_existing_roads, dataFileObject);
> 
>         Data::processDataFile("Data::read_neighbours", &Data::read_neighbours, dataFileObject);
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         cout << "Initializing group eligibility lists..." << endl;
>         tsb::InitGroupEligibilityLists();
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         cout << "Writing tables to binary file..." << endl;
>     	Table::serializeTableList(binaryWriter);
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         cout << "Writing groups to binary file..." << endl;
>     	Group::serializeGroupList(binaryWriter); // also serializes AxsDef members
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         cout << "Writing blocks to binary file..." << endl;
>         Block::serializeBlockList(binaryWriter); // also serializes neighbour Block objects
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         cout << "Writing zones to binary file..." << endl;
>         Zone::serializeZoneList(binaryWriter);
>         // also serializes AxsDef & Au members (including TimberClasses & Regens)
>         // zone serialization needs to be done after Block serialization for Block ID lookup
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         // priorities are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_priorities", &Data::read_priorities, dataFileObject);
> 
>         // transfers are not serialized (they may be manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_transfer", &Data::read_transfer, dataFileObject);
> 
>         // report flags are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_report_flags", &Data::read_report_flags, dataFileObject);
> 
>         //this->writeAll(binaryWriter);
>     }
>     else //read input from previous binary dump file (de-serialize)
>     {
>         // prepare to write (serialize) binary data to file
>         bool writing = false;
>         Serializer binaryReader(m_dataPath, m_binaryFileName, writing);
>         binaryReader.open();
> 
>         // config is not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_config", &Data::read_config, dataFileObject);
> 
>         // serialize m_enableRandomization flag; throws exception on read if doesn't match binary file
>         int randFlag = 0;
>         binaryReader.read( &(randFlag), sizeof(randFlag) );
>         if (m_enableRandomization != static_cast<bool>(randFlag))
>         {
> #ifdef _TSB_RAND_FLAG_DEBUG
>             cerr << "randFlag:" << randFlag << endl
>                  << "m_enableRandomization: " << m_enableRandomization << endl;
> #endif
>             string invalidValue("Inconsistent Randomization Flag: ");
>             if (randFlag)
>             {
>                 invalidValue += "(first: 'On', now: 'Off')";
>             }
>             else
>             {
>                 invalidValue += "(first: 'Off', now: 'On')";
>             }
>             string message("If you change randomization options in config.dat, you must re-run fssim with the '-u' flag. ");
> 
>             throw InvalidDataException(invalidValue, message);
>         }
> 
>         // time parameters are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_time_parameters", &Data::read_time_parameters, dataFileObject);
> 
>         cout << "Reading tables from binary file..." << endl;
>         dataFileObject.setFileName("FssimDump.bin (table)");
>     	Table::serializeTableList(binaryReader);
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>     	cout << "Reading groups from binary file..." << endl;
>     	dataFileObject.setFileName("FssimDump.bin (group)");
>     	Group::serializeGroupList(binaryReader); // also serializes AxsDef members
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         cout << "Reading blocks from binary file..." << endl;
>         dataFileObject.setFileName("FssimDump.bin (block)");
>         Block::serializeBlockList(binaryReader); // also serializes neighbour Block objects
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         cout << "Reading zones from binary file..." << endl;
>         dataFileObject.setFileName("FssimDump.bin (zone)");
>         Zone::serializeZoneList(binaryReader);
>         // also serializes AxsDef & Au members (including TimberClasses & Regens)
>         // zone serialization needs to be done after Block serialization for Block ID lookup
> 
> #ifdef _TSB_TIME_DEBUG
>         m_finish = clock();
>         cout << endl << "Duration of input processing: " << this->getDuration() << " (seconds)." << endl;
> #endif
> 
>         // targets are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_target", &Data::read_target, dataFileObject);
>         Data::processDataFile("Data::check_targets", &Data::check_targets, dataFileObject);
> 
>         // moved from before serialization to after
>         Data::processDataFile("Data::check_regen", &Data::check_regen, dataFileObject);
> 
>         // moved from before serialization to after
>         // priorities are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_priorities", &Data::read_priorities, dataFileObject);
> 
>         Data::processDataFile("Data::read_transfer", &Data::read_transfer, dataFileObject);
> 
>         // report flags are not serialized (they are manipulated by analysts across serial loads)
>         Data::processDataFile("Data::read_report_flags", &Data::read_report_flags, dataFileObject);
> 
>     	binaryReader.close();
>     }
>     m_pDataFileObject = 0; // re-set to null
> }
> 
> void FssimApp::deleteBlockList()
> {
>     cout << "Deleting block list..." << endl;
> 
>     typedef multimap<int, BlockStruct*>::iterator BI;
>     for (BI blockIter = m_blockList.begin(); blockIter != m_blockList.end(); ++blockIter)
>     {
>         init_delete_block(blockIter->second);
> 
>     }
>     m_blockList.clear();
> }
> 
> void FssimApp::deleteGroupList()
> {
>     cout << "Deleting group list..." << endl;
> 
>     typedef vector<GroupStruct*>::iterator GI;
>     for (GI groupIter = m_groupList.begin(); groupIter != m_groupList.end(); ++groupIter)
>     {
>         init_delete_group((*groupIter));
>     }
>     m_groupList.clear();
> }
> 
> void FssimApp::deleteZoneList()
> {
>     cout << "Deleting zone list..." << endl;
> 
>     typedef vector<ZoneStruct*>::iterator ZI;
>     for (ZI zoneIter = m_zoneList.begin(); zoneIter != m_zoneList.end(); ++zoneIter)
>     {
>         init_delete_zone(*zoneIter);
>     }
>     m_zoneList.clear();
> }
> 
> void FssimApp::deleteTableList()
> {
>     cout << "Deleting table list..." << endl;
> 
>     typedef map<int, TableStruct*>::iterator TI;
>     for (TI tableIter = m_tableList.begin(); tableIter != m_tableList.end(); ++tableIter)
>     {
>         TableStruct* pTable = tableIter->second;
>         init_delete_table(pTable);
>     }
>     m_tableList.clear();
> }
> 
> void FssimApp::cleanup_memory()
> {
>     cout << "Freeing memory..." << endl;
> 
>     this->deleteBlockList();
>     this->deleteZoneList();
>     this->deleteTableList();
>     this->deleteGroupList();
> 
>     cout << "Done" << endl;
> }
