0a1,2
> #ifndef _FUNC_H
> #define _FUNC_H
2,16c4,7
< extern int	func_agearea_index(int age, int NumAgeAreaElements, int period);
< extern int	func_upperage_from_index(int index, int period);
< extern int	func_group_membership(GROUP *group, int period, int when, char *zone, char *au, char *block, int age, int width, int ctype);
< extern double	func_vph(TABLE *table, int age);
< extern double	func_vph_recovered(CLASS *class);
< extern double	func_area_lt(double *agearea, int NumAgeAreaElements, int age, int period);
< extern double	func_area_ge(double *agearea, int NumAgeAreaElements, int age, int period);
< extern int	func_derive_integer(char *s);
< extern double	func_derive_float(char *s);
< extern ZONE 	*func_find_zone(char *label);
< extern GROUP	*func_find_group(char *label);
< extern TABLE	*func_find_table(char *label);
< extern AU	*func_find_au(ZONE *zone, char *label);
< extern BLOCK	*func_find_block(char *label);
< extern int 	func_compare_float(float f1, float f2);
---
> #include <math.h>	// for fabs()
> #include <ctype.h>
> #include <stdlib.h>
> #include <string.h>
17a9,338
> #include "defs.h"
> #include "hash.h"
> 
> /*extern*/ int	func_agearea_index(int age, int NumAgeAreaElements, int period);
> /*extern*/ int	func_upperage_from_index(int index, int period);
> /*extern*/ int	func_group_membership(GROUP *group, int period, int when, char *zone, char *au, char *block, int age, int width, int ctype);
> /*extern*/ double	func_vph(TABLE *table, int age);
> /*extern*/ double	func_vph_recovered(TIMBER_CLASS *timber_class);
> /*extern*/ double	func_area_lt(double *agearea, int NumAgeAreaElements, int age, int period);
> /*extern*/ double	func_area_ge(double *agearea, int NumAgeAreaElements, int age, int period);
> /*extern*/ int	func_derive_integer(char *s);
> /*extern*/ double	func_derive_float(char *s);
> /*extern*/ ZONE 	*func_find_zone(char *label);
> /*extern*/ GROUP	*func_find_group(char *label);
> /*extern*/ TABLE	*func_find_table(char *label);
> /*extern*/ AU	*func_find_au(ZONE *zone, char *label);
> /*extern*/ BLOCK	*func_find_block(char *label);
> /*extern*/ int 	func_compare_float(float f1, float f2);
> 
> extern inline int func_compare_float(float f1, float f2) {
> 	float tmp;
> 	tmp = fabs(f1-f2);
> 	if ( tmp < ROUND_ERROR ) {
> 		return(TRUE);
> 	} else {
> 		return(FALSE);
> 	}
> }
> 
> extern inline BLOCK* func_find_block(char *label) {
> 	BLOCK	*block;
> 	HASHREC	*hashrec;
> 
> 	blocklist = (LIST_PTR *)list_reset(blocklist);
> 	hashrec = (HASHREC *)list_next(blocklist);
> 	while (hashrec != NULL) {
> 		if (hashrec->id==(int)label[0]) {
> 			hashrec->candidates = (LIST_PTR *)list_reset(hashrec->candidates);
> 			block = (BLOCK *)list_next(hashrec->candidates);
> 			while (block != NULL) {
> 				if (strcmp(block->label, label)==0) {
> 					return(block);
> 				}
> 				block = (BLOCK *)list_next(hashrec->candidates);
> 			}
> 		}
> 		hashrec = (HASHREC *)list_next(blocklist);
> 	}
> 	return(NULL);
> }
> 
> extern inline ZONE* func_find_zone(char *label) {
> 	ZONE	*zone;
> 	zonelist = (LIST_PTR *)list_reset(zonelist);
> 	zone = (ZONE *)list_next(zonelist);
> 	while (zone != NULL) {
> 		if (strcmp(zone->label, label)==0) {
> 			return(zone);
> 		}
> 		zone = (ZONE *)list_next(zonelist);
> 	}
> 	return(NULL);
> }
> 
> extern inline GROUP* func_find_group(char *label) {
> 	GROUP	*group;
> 	group=NULL;
> 	grouplist = (LIST_PTR *)list_reset(grouplist);
> 	group = (GROUP *)list_next(grouplist);
> 	while (group != NULL) {
> 		if (strcmp(group->label, label)==0) {
> 			return(group);
> 		}
> 		group = (GROUP *)list_next(grouplist);
> 	}
> 	return(NULL);
> }
> 
> extern inline TABLE* func_find_table(char *label) {
> 	TABLE	*table;
> 	table=NULL;
> 	tablelist = (LIST_PTR *)list_reset(tablelist);
> 	table = (TABLE *)list_next(tablelist);
> 	while (table != NULL) {
> 		if (strcmp(table->label, label)==0) {
> 			return(table);
> 		}
> 		table = (TABLE *)list_next(tablelist);
> 	}
> 	return(NULL);
> }
> 
> extern inline AU* func_find_au(ZONE *zone, char *label) {
> 	AU	*au;
> 	zone->aulist = (LIST_PTR *)list_reset(zone->aulist);
> 	au = (AU *)list_next(zone->aulist);
> 	while (au!=NULL) {
> 		if (strcmp(au->label, label)==0) {
> 			return(au);
> 		}
> 		au = (AU *)list_next(zone->aulist);
> 	}
> 	return(NULL);
> }
> 
> extern inline int func_derive_integer(char *s) {
> 	int	i, ret;
> 	for(i=0;i<(int)strlen(s);i++) {
> 		if ((!isdigit(s[i]))&&(s[i]!='-')) {
> 			return(ERRORVAL);
> 		}
> 	}
> 	ret = atoi(s);
> 	return(ret);
> }
> 
> extern inline double func_derive_float(char *s) {
> 	int	i;
> 	double	ret;
> 	for(i=0;i<(int)strlen(s);i++) {
> 		if ((!isdigit(s[i]))&&(s[i]!='.')&&(s[i]!='-')) {
> 			return(ERRORVAL);
> 		}
> 	}
> 	ret = atof(s);
> 	return(ret);
> }
> 
> extern inline int func_agearea_index(int age, int NumAgeAreaElements, int period) {
> 	int	x;
> 	if (((age%period_length[period])==0)||(age<0)) {
> 		x = ((int)(age/period_length[period]))+1;
> 	} else {
> 		x = ((int)(age/period_length[period]))+2;
> 	}
> 	if (x<0) x=0;
> 	if (x>=NumAgeAreaElements) x=NumAgeAreaElements-1;
> 	return(x);
> }
> 
> extern inline int func_upperage_from_index(int index, int period) {
> 	return((index-1)*period_length[period]);
> }
> 
> extern inline double func_area_lt(double *agearea, int NumAgeAreaElements, int age, int period) {
> 	int	index,i;
> 	double	result;
> 	float	x,y;
> 
> 
> 	/* returns area < age (LESS THAN) */
> 	if (agearea==NULL) return(0.0);
> 	if (age<=-period_length[period]) {
> 		return(agearea[0]);
> 	}
> 	x = (float)(((float)(age-1+period_length[period]))/(float)period_length[period]);	/* proportion */
> 	index = (int)x; 	/* integer part */
> 	y = x-index;		/* float part */
> 	result=0.0;
> 	for(i=0;i<=index;i++) {
> 		result+=agearea[i];
> 	}
> 	result+=agearea[index+1]*y;
> 	return(result);
> }
> 
> extern inline double func_area_ge(double *agearea, int NumAgeAreaElements, int age, int period) {
> 	int	index,i;//mod;
> 	double	result;
> 	float	factor;
> 	/* returns area >= age (GREATER/EQUAL) */
> 	if (agearea==NULL) return(0.0);
> 	index = func_agearea_index(age, NumAgeAreaElements, period);
> 	factor = (float)((period_length[period]-(age%period_length[period])+1)%period_length[period])/(float)period_length[period];
> 	if (factor==0.0) factor=1.0;
> 	result=0.0;
> 	result+=agearea[index]*factor;
> 	for(i=index+1;i<NumAgeAreaElements;i++) {
> 		result+=agearea[i];
> 	}
> 	return(result);
> }
> 
> extern inline 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;
> 
> 	if ( when == BEFORE ) {
> 		offset = period_length[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 != NULL) {
> 		if ((group->grouptype==STATIC)&&(period==1)&&(when==BEFORE)) {
> 			/*
> 				STATIC 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, NULLSTR)==0)||(strcmp(gd->block,block)==0)) {
> 					if ((strcmp(gd->zone,NULLSTR)==0) && (strcmp(gd->au,NULLSTR)==0)) {
> 						if ((gd->class_type==DUMMYINPUT)||(ctype==gd->class_type)) return(TRUE); /* case 1 */
> 					} else if ((strcmp(gd->zone,NULLSTR)==0) && (strcmp(gd->au,au)==0)) {
> 						if ((gd->class_type==DUMMYINPUT)||(ctype==gd->class_type)) return(TRUE); /* case 2 */
> 					} else if ((strcmp(gd->zone,zone)==0) && (strcmp(gd->au,NULLSTR)==0)) {
> 						if ((gd->class_type==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==DUMMYINPUT)||(ctype==gd->class_type)) return(TRUE); /* case 4 */
> 					}
> 				}
> 			}
> 		} else if (group->grouptype==FLOAT) {
> 			/*
> 				FLOAT 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, NULLSTR)==0)||(strcmp(gd->block,block)==0)) {
> 					if ((strcmp(gd->zone,NULLSTR)==0) && (strcmp(gd->au,NULLSTR)==0)) {
> 						if ((gd->class_type==DUMMYINPUT)||(ctype==gd->class_type)) return(TRUE); /* case 1 */
> 					} else if ((strcmp(gd->zone,NULLSTR)==0) && (strcmp(gd->au,au)==0)) {
> 						if ((gd->class_type==DUMMYINPUT)||(ctype==gd->class_type)) return(TRUE); /* case 2 */
> 					} else if ((strcmp(gd->zone,zone)==0) && (strcmp(gd->au,NULLSTR)==0)) {
> 						if ((gd->class_type==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==DUMMYINPUT)||(ctype==gd->class_type)) return(TRUE); /* case 4 */
> 					}
> 				}
> 			}
> 		}
> 		gd = (GROUPDEF *)list_next(group->groupdefs);
> 	}
> 	return(FALSE);
> }
> 
> extern inline double func_vph(TABLE *table, int age) {
> 	double	result;
> 
> 	/*
> 		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 >= MAX_NUM_TABLE_VERTICES) {
> 		result = table->Volume[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);
> }
> 
> extern inline double func_vph_recovered(TIMBER_CLASS *timber_class) {
> 	REGEN	*regen;
> 	double	vph,regenvph,result;
> 	int	new_age;
> 
> 	if (timber_class==NULL) {
> 		printf("\n\nERROR: func_vph_recovered() passed NULL timber_class parameter\n\n");
> 		exit(-2);
> 	}
> 
> 	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==NULL) {
> 		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 != NULL) {
> 			/* may regenerate to original (or any) age */
> 			if (regen->ToAge==-INF) {
> 				new_age = timber_class->age+regen->Offset;
> 			} else {
> 				new_age = regen->ToAge+regen->Offset;
> 			}
> 			regenvph += func_vph(regen->au->table,new_age)*(regen->pc/100.0);
> 			/*printf("\nregen percent : %f", regen->pc);
> 			printf("\nregen ToAge : %d", regen->ToAge);
> 			printf("\nregen Offset : %d", regen->Offset);
> 			printf("\nregenvph: %f", regenvph);*/
> 			regen = (REGEN *)list_next(timber_class->parent_au->regenlist);
> 		}
> 	}
> 	result = vph-regenvph;
> 	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(-2);
> 	}
> 	return(result);
> }
> #endif
