alpar@9: #  Model I Forest Estate Modelling using GLPK/MathProg
alpar@9: #  Reading and writing dbf files
alpar@9: 
alpar@9: #  by Noli Sicad --- nsicad@gmail.com
alpar@9: # 18 December 2009
alpar@9: 
alpar@9: #  Forest Management 4th Edition 
alpar@9: #  by Lawrence Davis, K. Norman Johnson, Pete Bettinger, Theodore Howard
alpar@9: #  Chapter 11 - Daniel Pickett 
alpar@9: #  http://warnell.forestry.uga.edu/Warnell/Bettinger/mgtbook/index.htm
alpar@9: 
alpar@9: #  Model I Formulation
alpar@9: 
alpar@9: /*  Note: This is not the full LP model mentioned in the book.
alpar@9: Some of the constraints are deliberately omitted in this model for the purpose of clarity.
alpar@9: 
alpar@9: The features of MathProg in this example are:
alpar@9: * reading and writing dbf from regular dbf files,
alpar@9: * reading dbf file (database of shapefile (stands.shp)) (e.g. area parameter),
alpar@9: * using the area data in the constraints and
alpar@9: * writing dbf file from result of LP model.
alpar@9: 
alpar@9: Model I - Harvest Scheduling formulation for Sustainable Forest Management (SFM)
alpar@9: 
alpar@9: Features are:
alpar@9: * Net Present Value for the objective function (Revenue - Cost)
alpar@9: * Harvest Constraints by period - Sustainable Yield per Period
alpar@9: * Even-Flow Constraint / Volume - Harvest Flow Constraint -  Alpha (1-Apha)
alpar@9: * Even-Flow Constraint / Volume - Harvest Flow Constraint - Beta  (1 +Beta)
alpar@9: * Forest / Land Constraint -- Total Area of the forest
alpar@9: * Forest Stand Constraint  -- Individual stands
alpar@9: 
alpar@9: What is next? -- Forest Mgt Carbon Accounting for Climate Change
alpar@9: 
alpar@9: Note: The model file that the data containing in
alpar@9: the dbf files is public domain material (so it is compatible with the
alpar@9: GNU GPL) and data can be found in 
alpar@9: http://warnell.forestry.uga.edu/Warnell/Bettinger/mgtbook/index.htm
alpar@9: 
alpar@9: # Noli Sicad --- nsicad@gmail.com
alpar@9: 
alpar@9: */
alpar@9: 
alpar@9: set G_STAND_TYPE; # A, B, C
alpar@9: 
alpar@9: set I_CULTURAL_PRES; 
alpar@9: set J_MGT_YEAR; 
alpar@9: 
alpar@9: param K_PERIOD;
alpar@9: param Forest_Cost{G_STAND_TYPE,I_CULTURAL_PRES, J_MGT_YEAR}; # cost
alpar@9: 
alpar@9: param Yield_Table_Vol{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD} >= 0;
alpar@9: 
alpar@9: 
alpar@9: param Alpha >= 0;
alpar@9: param Beta >= 0;
alpar@9: 
alpar@9: param TCost_Table{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD} >= 0;
alpar@9: 
alpar@9: param NetRev_Table{G_STAND_TYPE, I_CULTURAL_PRES, J_MGT_YEAR, 1..K_PERIOD};
alpar@9: 
alpar@9: 
alpar@9: var XForestLand{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} >= 0;
alpar@9: 
alpar@9: 
alpar@9: #reading dbf tables
alpar@9: table tab IN "xBASE" "standtype.dbf": G_STAND_TYPE <- [STAND];
alpar@9: display G_STAND_TYPE;
alpar@9: 
alpar@9: 
alpar@9: table tab2 IN "xBASE" "cultural_pres.dbf": I_CULTURAL_PRES <- [CUL_PRES];
alpar@9: display I_CULTURAL_PRES;
alpar@9: 
alpar@9: table tab3 IN "xBASE" "mgt_year.dbf": J_MGT_YEAR <- [MGT_YEAR];
alpar@9: display J_MGT_YEAR;
alpar@9: 
alpar@9: /*
alpar@9: param Forest_Cost{G_STAND_TYPE,I_CULTURAL_PRES, J_MGT_YEAR} default 0; # cost
alpar@9: */
alpar@9: 
alpar@9: set S1, dimen 3;
alpar@9: table tab4 IN "xBASE" "Forest_Cost.dbf": S1 <- [STAND, CUL_PRES, MGT_YEAR],Forest_Cost ~FCOST;
alpar@9: display Forest_Cost;
alpar@9: 
alpar@9: set S2, dimen 4;
alpar@9: table tab5 IN "xBASE" "Yield_Table_Vol.dbf": S2 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],Yield_Table_Vol ~YIELD;
alpar@9: display Yield_Table_Vol;
alpar@9: 
alpar@9: set S3, dimen 4;
alpar@9: table tab5 IN "xBASE" "TCost_Table.dbf": S3 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],TCost_Table ~TCOST;
alpar@9: display TCost_Table;
alpar@9: 
alpar@9: 
alpar@9: set S4, dimen 4;
alpar@9: table tab5 IN "xBASE" "NetRev_Table.dbf": S4 <- [STAND, CUL_PRES, MGT_YEAR, PERIOD],NetRev_Table ~NETREV;
alpar@9: display NetRev_Table;
alpar@9: 
alpar@9: 
alpar@9: param MGT;
alpar@9: 
alpar@9: param Area_Stand_Indi{g in G_STAND_TYPE, m in 1..MGT} default 0; 
alpar@9: 
alpar@9: set ST, dimen 2;
alpar@9: table tab5 IN "xBASE" "stands.dbf": ST <- [VEG_TYPE, MGT], Area_Stand_Indi ~ACRES;
alpar@9: display Area_Stand_Indi;
alpar@9: 
alpar@9: param Area_Stand_Type{g in G_STAND_TYPE}:= sum {m in 1..MGT } Area_Stand_Indi[g,m];
alpar@9: display Area_Stand_Type;
alpar@9: 
alpar@9: 
alpar@9: param Total_Area := sum {g in G_STAND_TYPE, m in 1..MGT } Area_Stand_Indi[g,m];
alpar@9: display Total_Area;
alpar@9: 
alpar@9: param Harvest_Min_Vol_Period;
alpar@9: 
alpar@9: 
alpar@9: var NetPresentValue;
alpar@9: 
alpar@9: # Objective function
alpar@9: maximize Net_Present_Value: NetPresentValue;
alpar@9: 
alpar@9: subject to NPV:
alpar@9:    NetPresentValue = sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Forest_Cost[g,i,j] * XForestLand[g,i,j];
alpar@9: 
alpar@9: # Harvest Constraint by Period
alpar@9: subject to Harvest_Period_H {k in 1..K_PERIOD}:
alpar@9:    sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] >= Harvest_Min_Vol_Period;
alpar@9:    
alpar@9: 
alpar@9: #Even-Flow Constraint / Volume - Harvest Flow Constraint - Alpha
alpar@9: subject to Even_Flow_Constaints_Alpha {k in 6..K_PERIOD-1}:
alpar@9:     (1 - Alpha) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] -
alpar@9:     sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j] <= 0;
alpar@9: 
alpar@9: # Even-Flow Constraint / Volume - Harvest Flow Constraint - Beta
alpar@9: subject to Even_Flow_Constaints_Beta {k in 6..K_PERIOD-1}:
alpar@9:     (1 + Beta) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] -
alpar@9:     sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j] >= 0;
alpar@9:    
alpar@9: # Forest / Land Constraints
alpar@9: subject to Total_Area_Constraint: 
alpar@9:   sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} XForestLand[g,i,j] <= Total_Area;
alpar@9: display Total_Area;   
alpar@9: 
alpar@9: # Forest / Land Constraints for A B C
alpar@9: subject to Area {g in G_STAND_TYPE}:
alpar@9:    sum {i in I_CULTURAL_PRES,j in J_MGT_YEAR} XForestLand[g,i,j] = Area_Stand_Type[g];
alpar@9: 
alpar@9: 
alpar@9: 
alpar@9: solve;
alpar@9: #RESULT SECTION
alpar@9: printf '#################################\n';
alpar@9: printf 'Forest Management Model I - Noli Sicad\n';
alpar@9: printf '\n';
alpar@9: printf 'Net Present Value = %.2f\n', NetPresentValue;
alpar@9: printf '\n';
alpar@9: 
alpar@9: printf '\n';
alpar@9: printf 'Variables\n';
alpar@9: printf 'Stand_Type  Age_Class  Mgt_Presc  Sign Value \n';
alpar@9: printf{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR}:'%5s %10s %11s = %10.2f\n', g,i,j, XForestLand[g,i,j]; 
alpar@9: printf '\n';
alpar@9: 
alpar@9: printf 'Constraints\n';
alpar@9: printf 'Period Harvest Sign \n';
alpar@9: for {k in 1..K_PERIOD} {
alpar@9:  printf '%5s %10.2f >= %.3f\n', k, sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j], Harvest_Min_Vol_Period;
alpar@9:    }
alpar@9: 
alpar@9: # xbase (dbf) output
alpar@9: table Harvest{k in 1..K_PERIOD} OUT "xBASE" "HarvestArea1.dbf" "N(5)N(15,2)" :  k ~ Period, (sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j]) ~ H_Area;
alpar@9: 
alpar@9: # xbase (dbf) read
alpar@9: set S, dimen 2;
alpar@9: table tab2 IN "xBASE" "HarvestArea1.dbf": S <- [Period, H_Area];
alpar@9: display S;
alpar@9: 
alpar@9: 
alpar@9: 
alpar@9: 
alpar@9: printf '\n';
alpar@9: printf 'Constraint\n';
alpar@9: printf 'Harvest Period\n';
alpar@9: printf 'Type AgeClass  PrescMgt Period    Value\n';
alpar@9: printf{g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR, k in 1..K_PERIOD}:'%5s %11s %11s %5s %10.2f\n', g,i,j, k, (Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j]); 
alpar@9: 
alpar@9: 
alpar@9: printf 'Even_Flow_Constaint_Alpha (1-Alpha)\n';
alpar@9: printf 'Period Sign \n';
alpar@9: for {k in 6..K_PERIOD-1} {
alpar@9:    printf "%s %10.2f <= %s\n", k, ((1 - Alpha) * sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k] * XForestLand[g,i,j] - sum {g in G_STAND_TYPE,i in I_CULTURAL_PRES, j in J_MGT_YEAR} Yield_Table_Vol[g,i,j,k+1] * XForestLand[g,i,j]),0;
alpar@9:   }
alpar@9: printf '\n';
alpar@9: 
alpar@9: 
alpar@9: # Forest / Land Constraints
alpar@9: printf '\n';  
alpar@9: printf 'Total Area Constraint\n';
alpar@9: printf 'Type AgeClass  PrescMgt  Value Sign Total_Area \n';
alpar@9: printf '%5s <= %.3f\n',sum {g in G_STAND_TYPE, i in I_CULTURAL_PRES, j in J_MGT_YEAR} XForestLand[g,i,j], Total_Area;
alpar@9: 
alpar@9: printf 'Area\n';
alpar@9: printf 'Area Value Sign Areas_Stand\n';
alpar@9: for {g in G_STAND_TYPE} {
alpar@9:   printf '%5s %10.2f <= %.3f\n', g, sum {i in I_CULTURAL_PRES,j in J_MGT_YEAR} XForestLand[g,i,j],  Area_Stand_Type[g];
alpar@9:    }
alpar@9: 
alpar@9: 
alpar@9: #DATA SECTION 
alpar@9:       
alpar@9: data;
alpar@9: 
alpar@9: # Most of the data has been moved to dbf format
alpar@9: 
alpar@9: param MGT:=31;
alpar@9: 
alpar@9: param K_PERIOD:= 7;
alpar@9: 
alpar@9: param Alpha:= 0.20;
alpar@9: param Beta:= 0.20;
alpar@9: 
alpar@9: param Harvest_Min_Vol_Period:= 12000;
alpar@9: 
alpar@9: end;
alpar@9: