1,13d0
< #include <iostream>
< #include <iomanip>
< #include <string>
< 
< #include <cstdlib> // exit()
< //#include <clocale> // isdigit()
< #include <cstdio>
< 
< #include <cmath>	// fabs()
< #include <cctype> // isdigit(int)
< #include <cstring>
< 
< 
15,526d1
< 
< #include "report.h"
< 
< using namespace std;
< 
< namespace tsb
< {
<     /* inlined
<     int func_compare_float(float f1, float f2)
<     {
<         float tmp;
<         // cast from float to double
<         tmp = static_cast<double>(fabs(f1-f2));
<         //tmp = static_cast<double>((f1-f2)); // MATH MISTAKE!!! (intentional)
<         if ( tmp < FssimApp::m_kRoundError )
<         {
<             return(true);
<         } else {
<             return(false);
<         }
<     }
< 
<     BLOCK* func_find_block(char *label)
<     {
<         BLOCK	*block;
<         HASHREC	*hashrec;
<         FssimApp* pApp = FssimApp::getApp();
< 
<         pApp->m_blockList = (LIST_PTR *)List::reset(pApp->m_blockList);
<         hashrec = (HASHREC *)List::next(pApp->m_blockList);
<         while (hashrec != 0)
<         {
<             if (hashrec->id == static_cast<int>(label[0]))
<             {
<                 hashrec->candidates = (LIST_PTR *)List::reset(hashrec->candidates);
<                 block = (BLOCK *)List::next(hashrec->candidates);
<                 while (block != 0)
<                 {
<                     if (strcmp(block->label, label) == 0)
<                     {
<                         return block;
<                     }
<                     block = (BLOCK *)List::next(hashrec->candidates);
<                 }
<             }
<             hashrec = (HASHREC *)List::next(pApp->m_blockList);
<         }
<         return 0;
<     }
< 
< 
<     ZONE* func_find_zone(char *label)
<     {
<         ZONE* zone = 0;
<         FssimApp* pApp = FssimApp::getApp();
<         pApp->m_zoneList = (LIST_PTR *)List::reset(pApp->m_zoneList);
<         zone = (ZONE *)List::next(pApp->m_zoneList);
<         while (zone != 0)
<         {
<             if (strcmp(zone->label, label)==0)
<             {
<                 return zone;
<             }
<             zone = (ZONE *)List::next(pApp->m_zoneList);
<         }
<         return 0;
<     }
< 
< 
<     GROUP* func_find_group(char *label)
<     {
<         GROUP* group;
<         group = 0;
<         FssimApp* pApp = FssimApp::getApp();
<         pApp->m_groupList = (LIST_PTR *)List::reset(pApp->m_groupList);
<         group = (GROUP *)List::next(pApp->m_groupList);
<         while (group != 0)
<         {
<             if (strcmp(group->label, label) == 0)
<             {
<                 return group;
<             }
<             group = (GROUP *)List::next(pApp->m_groupList);
<         }
<         return 0;
<     }
< 
<     GROUP* func_find_group(int id)
<     {
<         GROUP* group;
<         group = 0;
<         FssimApp* pApp = FssimApp::getApp();
<         pApp->m_groupList = (LIST_PTR *)List::reset(pApp->m_groupList);
<         group = (GROUP *)List::next(pApp->m_groupList);
<         while (group != 0)
<         {
<             if (group->id == id)
<             {
<                 return group;
<             }
<             group = (GROUP *)List::next(pApp->m_groupList);
<         }
<         return 0;
<     }
< 
<     TABLE* func_find_table(char *label)
<     {
<         TABLE	*table;
<         table = 0;
<         FssimApp* pApp = FssimApp::getApp();
<         pApp->m_tableList = (LIST_PTR *)List::reset(pApp->m_tableList);
<         table = (TABLE *)List::next(pApp->m_tableList);
<         while (table != 0)
<         {
<             if (strcmp(table->label, label) == 0)
<             {
<                 return table;
<             }
<             table = (TABLE *)List::next(pApp->m_tableList);
<         }
<         return 0;
<     }
< 
<     TABLE* func_find_table(int id)
<     {
<         TABLE	*table;
<         table = 0;
<         FssimApp* pApp = FssimApp::getApp();
<         pApp->m_tableList = (LIST_PTR *)List::reset(pApp->m_tableList);
<         table = (TABLE *)List::next(pApp->m_tableList);
<         while (table != 0)
<         {
<             if (table->id == id)
<             {
<                 return table;
<             }
<             table = (TABLE *)List::next(pApp->m_tableList);
<         }
<         return 0;
<     }
< 
<     AU* func_find_au(ZONE *zone, char *label)
<     {
<         AU* au;
<         zone->aulist = (LIST_PTR *)List::reset(zone->aulist);
<         au = static_cast<AU*>(List::next(zone->aulist));
<         while (au != 0)
<         {
<             if (strcmp(au->label, label) == 0)
<             {
<                 return au;
<             }
<             au = static_cast<AU*>(List::next(zone->aulist));
<         }
<         return 0;
<     }
< 
<     int func_derive_integer(char *s)
<     {
<         int	ret;
<         for(int i = 0 ; i<(int)strlen(s) ; ++i)
<         {
<             if ( ( !isdigit(s[i]) ) && ( s[i]!='-' ) )
<             {
<                 return(FssimApp::ERRORVAL);
<             }
<         }
<         ret = atoi(s);
<         return(ret);
<     }
< 
<     double func_derive_float(char *s)
<     {
<         double	ret;
<         for(int i=0 ; i < static_cast<int>(strlen(s)) ; ++i)
<         {
<             if ((!isdigit(s[i])) && (s[i] != '.') && (s[i] != '-'))
<             {
<                 return(FssimApp::ERRORVAL);
<             }
<         }
<         ret = atof(s);
<         return(ret);
<     }
< 
<     int func_agearea_index(int age, int NumAgeAreaElements, int period)
<     {
<         int	index = 0;
<         FssimApp* pApp = FssimApp::getApp();
< 
<         // if age is negative or the last (0th) year of a period,
<         // assign to agearea bin of preceding years
<         // e.g., for a 10-yr period, yr 80 is assigned to the same agearea bin (index 9) as yrs 71 through 79
<         if ( ((age % (pApp->m_periodLength[period])) == 0) || (age < 0) )
<         {
<             index = ( static_cast<int>( (age / (pApp->m_periodLength[period]) ) ) + 1 );
<         }
<         else // if age is between the 1st and 2nd-last year of a period, inclusive
<         {
<             index = ( static_cast<int>( (age / (pApp->m_periodLength[period]) ) ) + 2 );
<         }
<         if (index < 0)  // if age was originally more negative than the period length, assign
<                         // to same agearea bin as years -((3*periodLength)-1) through -(periodLength)
<                         // e.g., for a 10-year period, years -29 through -10 are assigned to bin index 0 (zero)
<                         // along with years -30 and more negative which produce negative indices
<         {               // in the above statement
<             index = 0;
<         }
<         if (index >= NumAgeAreaElements) // assign all really old timber classes to last bin of agearea array
<         {
<             index = NumAgeAreaElements - 1;
<         }
<         return index;
<     }
< 
<     int func_upperage_from_index(int index, int period)
<     {
<     	FssimApp* pApp = FssimApp::getApp();
<         int upperAge = (index - 1) * ( pApp->m_periodLength[period] );
<         return upperAge;
<     }
< 
<     double func_area_lt(double *agearea, int age, int period)
<     {
<         FssimApp* pApp = FssimApp::getApp();
< 
<         // returns area < age (LESS THAN)
<         if (agearea == 0)
<         {
<         	return 0.0;
<         }
< 
<         if ( age <= -(pApp->m_periodLength[period]) )
<         {
<             return agearea[0];
<         }
< 
<         float x = static_cast<float>(age - 1 + pApp->m_periodLength[period]) /
<                   static_cast<float>(pApp->m_periodLength[period]);	// proportion
< 
<         int index = static_cast<int>(x); 	// integer part
<         float y = x - index;		// float part
<         double result = 0.0;
<         for(int i = 0 ; i <= index ; i++)
<         {
<             result += agearea[i];
<         }
<         result += agearea[index + 1] * y;
<         return result;
<     }
< 
<     // width added in v4.0.1 to account for width = 1 at time zero
<     double func_area_ge(double* agearea, int NumAgeAreaElements, int age, int period)
<     {
<         FssimApp* pApp = FssimApp::getApp();
< 
<         // returns area >= age (GREATER/EQUAL)
<         if (agearea == 0)
<         {
<             return 0.0;
<         }
< 
<         // calculate the percentage of the age area elements at the constraint age
<         // which will have partially reached the given age by the end of the period
<         int thisPeriodLength = pApp->m_periodLength[period];
<         float factor = static_cast<float>( (thisPeriodLength - (age % thisPeriodLength) + 1) % thisPeriodLength ) /
<                        static_cast<float>(thisPeriodLength);
< 
< 
< #ifdef _TSB_GEFACTOR_DEBUG
<         cout << endl << setw(43) << "factor before adjustment = "
<              << setprecision(2) << factor << endl;
< #endif
< 
<         if (factor == 0.0)
<         {
<             factor = 1.0;
<         }
< 
< */
< // temporarily commented out to rectify v4.1a with v4.0
< /*
<         // pApp->m_applyFactor added in v4.0.2 to remove recursive factoring
<         if (!pApp->m_applyFactor)
<         {
< #ifdef _TSB_GEFACTOR_DEBUG
<             cout << "apply factor is false" << endl;
< #endif
<             factor = 1.0;
<         }
< */
< /*
<         double areaGreaterOrEqual = 0.0;
<         int index = func_agearea_index(age, NumAgeAreaElements, period);
< 
<         // take only a percentage of the age area element which overlaps the contraint age
<         areaGreaterOrEqual += agearea[index] * factor;
< 
< #ifdef _TSB_GEFACTOR_DEBUG
<         cout << setw(20) << "area_ge(before) = " << setw(8) << setprecision(8) << areaGreaterOrEqual
<              << setw(20) << "age = " << setprecision(3) << setw(3) << age
<              << setw(20) << "NumEl = " << setw(3) << NumAgeAreaElements << endl;
< #endif
< 
<         // sum up all age area elements older than the constraint age
<         for( int i = index + 1 ; i < NumAgeAreaElements ; ++i)
<         {
<             areaGreaterOrEqual += agearea[i];
<         }
< 
< #ifdef _TSB_GEFACTOR_DEBUG
<         cout << setw(20) << "areaGreaterOrEqual = " << setw(8) << setprecision(8) << areaGreaterOrEqual
<              << setw(20) << "index = " << setprecision(3) << setw(3) << index
<              << setw(20) << "factor = " << setw(3) << factor << endl;
< #endif
< 
<         return areaGreaterOrEqual;
<     }
< 
<     int func_group_membership(GROUP *group, int period, int when, char *zone, char *au, char *block, int age, int width, int ctype)
<     {
<         GROUPDEF	*gd;
<         int		offset;
<         FssimApp* pApp = FssimApp::getApp();
< 
<         if ( when == FssimApp::BEFORE )
<         {
<             offset = pApp->m_periodLength[period];
<         } else {
<             offset = 0;
<         }
< 
< 
<         // Iterate through all groupdefs records, looking for a match
<         // If ages match; eight cases:   Zone      AU      Block
<         //1)	-	-        -
<         //1)	-	-        z
<         //2)	-	y        -
<         //2)	-	y        z
<         //3)	x	-        -
<         //3)	x	-        z
<         //4)	x	y        -
<         //4)	x	y        z
< 
<         group->groupdefs = (LIST_PTR *)List::reset(group->groupdefs);
<         gd = (GROUPDEF *)List::next(group->groupdefs);
<         while (gd != 0)
<         {
<             if ((group->grouptype==FssimApp::STATIC_GROUP)&&(period==1)&&(when==FssimApp::BEFORE))
<             {
< 
<             //FssimApp::STATIC_GROUP groups do not use look-ahead for membership;
<             //assess membership at time 0 - beginning of planning horizon
<             //before any aging takes place
< 
<                 if ((age>=gd->low_age)&&(age<=gd->high_age)||
<                     ((age-width+1)>=gd->low_age)&&((age-width+1)<=gd->high_age)||
<                     ((age-width+1)<=gd->low_age)&&(age>=gd->high_age))
<                 {
<                     if ((strcmp(gd->block, FssimApp::m_kNullString)==0)||(strcmp(gd->block,block)==0))
<                     {
<                         if ((strcmp(gd->zone,FssimApp::m_kNullString)==0) && (strcmp(gd->au,FssimApp::m_kNullString)==0))
<                         {
<                             if ((gd->class_type==FssimApp::DUMMYINPUT)||(ctype==gd->class_type)) return(true); // case 1
<                         } else if ((strcmp(gd->zone,FssimApp::m_kNullString)==0) && (strcmp(gd->au,au)==0))
<                         {
<                             if ((gd->class_type==FssimApp::DUMMYINPUT)||(ctype==gd->class_type)) return(true); // case 2
<                         } else if ((strcmp(gd->zone,zone)==0) && (strcmp(gd->au,FssimApp::m_kNullString)==0))
<                         {
<                             if ((gd->class_type==FssimApp::DUMMYINPUT)||(ctype==gd->class_type)) return(true); // case 3
<                         } else if ((strcmp(gd->zone,zone)==0) && (strcmp(gd->au,au)==0))
<                         {
<                             if ((gd->class_type==FssimApp::DUMMYINPUT)||(ctype==gd->class_type)) return(true); // case 4
<                         }
<                     }
<                 }
<             } else if (group->grouptype==FssimApp::FLOAT_GROUP)
<             {
< 
<             //FssimApp::FLOAT_GROUP and REPORT type groups use look-ahead for membership;
<             //if timber_class ages will age into group or
<             //timber_class ages out of group during period, consider
<             //timber_class to be member
< 
<                 if (((age+offset)<gd->low_age)||((age-width+1)>gd->high_age))
<                 {
<                     // NON MEMBER
<                 } else {
<                     // MEMBER
<                     if ((strcmp(gd->block, FssimApp::m_kNullString)==0)||(strcmp(gd->block,block)==0))
<                     {
<                         if ((strcmp(gd->zone,FssimApp::m_kNullString)==0) && (strcmp(gd->au,FssimApp::m_kNullString)==0))
<                         {
<                             if ((gd->class_type==FssimApp::DUMMYINPUT)||(ctype==gd->class_type)) return(true); // case 1
<                         } else if ((strcmp(gd->zone,FssimApp::m_kNullString)==0) && (strcmp(gd->au,au)==0))
<                         {
<                             if ((gd->class_type==FssimApp::DUMMYINPUT)||(ctype==gd->class_type)) return(true); // case 2
<                         } else if ((strcmp(gd->zone,zone)==0) && (strcmp(gd->au,FssimApp::m_kNullString)==0))
<                         {
<                             if ((gd->class_type==FssimApp::DUMMYINPUT)||(ctype==gd->class_type)) return(true); // case 3
<                         } else if ((strcmp(gd->zone,zone)==0) && (strcmp(gd->au,au)==0))
<                         {
<                             if ((gd->class_type==FssimApp::DUMMYINPUT)||(ctype==gd->class_type)) return(true); // case 4
<                         }
<                     }
<                 }
<             }
<             gd = (GROUPDEF *)List::next(group->groupdefs);
<         }
<         return(false);
<     }
< 
<     double
<     func_vph(TABLE *table, int age)
<     {
<         double result = 0.0;
< 
< 
<         //OAFs are applied to tables in data_implement_table_oafs()
<         //No need to apply OAFs here; straight table lookup
< 
<         if (age < 0)
<         {
<             result = 0.0;
<         } else if (age >= FssimApp::MAX_NUM_TABLE_VERTICES)
<         {
<             result = table->Volume[FssimApp::MAX_NUM_TABLE_VERTICES-1];
<         } else {
<             result = table->Volume[age];
<             //printf("\nage: %d", age);
<             //printf("\ntable->Volume[age]: %f", table->Volume[age]);
<     		//printf("\ntable->id: %d", table->id);
<     		//printf("\ntable->label: %s", table->label);
<         }
<         return(result);
<     }
< 
<     double
<     func_vph_recovered(TIMBER_CLASS *timber_class)
<     {
<         REGEN	*regen;
<         double	vph = 0.0;
<         double regenvph = 0.0;
<         double result = 0.0;
<         int	new_age;
< 
<         if (timber_class== 0)
<         {
<             printf("\n\nERROR: func_vph_recovered() passed 0 timber_class parameter\n\n");
<             exit(1);
<         }
< 
<         vph = func_vph(timber_class->parent_au->table, timber_class->age);
<         //printf("\nvph 1: %f", vph);
<         //printf("\ntimber_class age: %d", timber_class->age);
<         if (timber_class->parent_au->regenlist== 0)
<         {
<             regenvph = func_vph(timber_class->parent_au->table, 0);
<         } else {
<             regenvph = 0.0;
<             timber_class->parent_au->regenlist = (LIST_PTR *)List::reset(timber_class->parent_au->regenlist);
<             regen = (REGEN *)List::next(timber_class->parent_au->regenlist);
<             while (regen != 0)
<             {
<                 // may regenerate to original (or any) age
<                 if (regen->ToAge==-FssimApp::INFINITY)
<                 {
<                     new_age = timber_class->age+regen->Offset;
<                 }
<                 else
<                 {
<                     new_age = regen->ToAge+regen->Offset;
<                 }
< #ifdef _TSB_REGEN_DEBUG
<             	cout << endl << "func_vph_recovered: new age: " << new_age << endl;
<     			cout << "func_vph_recovered: regen percent : " << regen->percent << endl;
<     			cout << "func_vph_recovered: regen ToAge : " << regen->ToAge << endl;
<     			cout << "func_vph_recovered: regen Offset : " << regen->Offset << endl;
< #endif
<                 if (0 != regen->au && 0 != regen->au->table)
<                 {
<                     regenvph += func_vph(regen->au->table,new_age)*(regen->percent/100.0);
<                     regen = (REGEN *)List::next(timber_class->parent_au->regenlist);
<                 }
<                 else
<                 {
<                     string message = "func_vph_recovered: regen->au or regen->au->table is null. Au label: ";
<                     message += timber_class->parent_au->label;
<                     throw message;
<                 }
<             }
<         }
<         result = vph-regenvph;
< #ifdef _TSB_FUNC_VPH_DEBUG
<         cout << endl << "func_vph_recovered (end): vph-regenvph: " << result << endl;
< #endif
<         if (result<0.0)
<         {
<             printf("\n\nERROR: func_vph_recovered() returned NEGATIVE m3/ha" );
<             printf("\n\t          Zone: %s", timber_class->parent_zone->label );
<             printf("\n\t            AU: %s", timber_class->parent_au->table->label );
<             printf("\n\t           Age: %d", timber_class->age );
<             printf("\n\t Pre-Regen VPH: %.2f", vph );
<             printf("\n\tPost-Regen VPH: %.2f", regenvph );
<             printf("\n\t Resultant VPH: %.2f\n\n", result );
<             exit(1);
<         }
<         return(result);
<     }
<     */
< } // end namespace tsb
< 
