### GeolUnitArea.sml
## 26 January 2006
## R. Smith
## MicroImages, Inc.
## standalone script to process sample points and basins
#$ created by the SampleCatchments script.
## Input: Results vector object containing relocated sample points and
## USDbasins vector containing basins (catchments) associated with
## sample points.
## Output: copy of the USDbasins vector with added GeolUnitArea table
## in the polygon database with records attached to polygon elements.
## Fields in this table record summed areas and percentages of each
## rock unit for each basin (catchment area).
## Assumption 1: Polygons have attached PERCENTAGE table created by
## the Polygon Properties process. Multiple records in this table are
## attached to each basin polygon, one for each geologic map
## unit polygon that overlaps the basin polygon. Each such record
## includes the area (in square meters) of the current basin polygon that
## is covered by that rock unit polygon. More than one rock unit polygon
## of the same type can overlap a given basin polygon.
## Assumption 2: Basins can be composite, consisting
## of more than one polygon element.
## Assumption 3: The sample for a particular basin represents it and
## all upstream basins in the same watershed. The PointToPoint table
## records the number of upstream samples for each sample, and the
## IDs of those that are immediately adjacent to that sample's basin.
## Compiling a list of all upstream basins requires a recursive
## procedure to exhaustively trace these upstream-adjacent relationships.
## Assumption 4: Geologic map units in the area are indicated by symbols
## Cu, Du, Mu, Ou, Qal, Tg, Ts, Tv, pCgr, and pCgs in the PERCENTAGE table.
## Global variables
class VECTOR SampleVect, BasinVectIn, BasinVectOut;
class STRINGLIST idList;
class DATABASE polyDB;
class DBTABLEINFO ptTable, basinInfoTbl, unitAreaTbl, percentTbl;
class DBFIELDINFO sampID, sampIDunit, totArea, checkArea;
class DBFIELDINFO cuAreaFld, cuPctFld, duAreaFld, duPctFld, muAreaFld, muPctFld, ouAreaFld;
class DBFIELDINFO ouPctFld, qalAreaFld, qalPctFld, tgAreaFld, tgPctFld, tsAreaFld, tsPctFld;
class DBFIELDINFO pCgrAreaFld, pCgrPctFld, pCgsAreaFld, pCgsPctFld, tvAreaFld, tvPctFld;
class DBFIELDINFO totUnitPctFld;
numeric i;
##########################################################################
## define recursive function to get upstream sample IDs from given sample
proc getUpstreamIDs ( string sampleID$ )
{
local numeric j;
local string fieldbase$ = "UpSample"; # base string for numbered UpSample fields
# add current sample ID to global ID List;
idList.AddToEnd(sampleID$);
# get record number in PointToPoint table for current sample ID
local numeric recNum = TableKeyFieldLookup(ptTable, "REC_NO", sampleID$);
# get number of upstream samples immediately adjacent to the current basin
local numeric numAdjUp = TableReadFieldNum(ptTable, "NumUpSamples", recNum);
if ( numAdjUp > 0 ) # if there are adjacent upstream polygons
{
# get list of sample IDs for adjacent upstream samples from UpSample[num] fields
# in the PolyToPoly table
local class STRINGLIST tempList;
for j = 1 to numAdjUp
{
# create string for field name holding the appropriate UpSample basin ID
# and add to local stringlist
local string field$ = fieldbase$ + NumToStr(j);
tempList.AddToEnd( TableReadFieldStr(ptTable, field$, recNum) );
}
# loop through local list of UpSample fields to get their adjacent upstream basin IDs
# and call procedure to check for basins further upstream
for j = 1 to numAdjUp
{
getUpstreamIDs( tempList[j-1] );
}
}
}
############################################################
################### Main process ###########################
############################################################
clear(); # clear Console window
###############################################################
## Get input vector and handles for existing tables needed for processing
GetInputVector(SampleVect);
GetInputVector(BasinVectIn);
GetOutputVector(BasinVectOut);
VectorCopyElements(BasinVectIn, BasinVectOut);
CloseVector(BasinVectIn);
# get handles for existing point and polygon tables needed for processing
ptTable = TableGetInfo(SampleVect.point.PointToPoint);
basinInfoTbl = TableGetInfo(BasinVectOut.poly.PolyToPoly);
sampID = FieldGetInfoByName(basinInfoTbl, "REC_NO"); # get DBFIELDINFO for REC_NO field
totArea = FieldGetInfoByName(basinInfoTbl, "TotalArea_sq_km");
percentTbl = TableGetInfo(BasinVectOut.poly.PERCENTAGE);
#########################################################
## create new polygon table
polyDB = OpenVectorPolyDatabase(BasinVectOut);
unitAreaTbl = TableCreate(polyDB, "UnitArea", "Geologic unit areas per basin");
unitAreaTbl.RelatedOnly = 1;
# create REC_NO field in GraniteArea table and make it foreign
# key field pointing to same field in PolyToPoly table
sampIDunit = TableAddFieldString(unitAreaTbl, "REC_NO", 12);
sampIDunit.IsPrimaryKey = 0;
sampIDunit.IsKey = 1;
sampIDunit.Key = sampID;
# add TotalArea_sq_km field in new table using DBFIELDINFO from same field in PolyToPoly
TableAddField(unitAreaTbl, totArea);
# add CheckArea field to verify if search of upstream IDs succeeded
checkArea = TableAddFieldFloat(unitAreaTbl, "CheckArea", 10, 4);
checkArea.UnitType = "Area";
checkArea.Units = "square kilometers";
# add fields for area and % for each rock unit
cuAreaFld = TableAddFieldFloat(unitAreaTbl, "Cu_Area", 10, 4);
cuPctFld = TableAddFieldFloat(unitAreaTbl, "Cu_Pct", 10, 2);
duAreaFld = TableAddFieldFloat(unitAreaTbl, "Du_Area", 10, 4);
duPctFld = TableAddFieldFloat(unitAreaTbl, "Du_Pct", 10, 2);
muAreaFld = TableAddFieldFloat(unitAreaTbl, "Mu_Area", 10, 4);
muPctFld = TableAddFieldFloat(unitAreaTbl, "Mu_Pct", 10, 2);
ouAreaFld = TableAddFieldFloat(unitAreaTbl, "Ou_Area", 10, 4);
ouPctFld = TableAddFieldFloat(unitAreaTbl, "Ou_Pct", 10, 2);
qalAreaFld = TableAddFieldFloat(unitAreaTbl, "Tg_Area", 10, 4);
qalPctFld = TableAddFieldFloat(unitAreaTbl, "Tg_Pct", 10, 2);
tgAreaFld = TableAddFieldFloat(unitAreaTbl, "Tg_Area", 10, 4);
tgPctFld = TableAddFieldFloat(unitAreaTbl, "Tg_Pct", 10, 2);
tsAreaFld = TableAddFieldFloat(unitAreaTbl, "Ts_Area", 10, 4);
tsPctFld = TableAddFieldFloat(unitAreaTbl, "Ts_Pct", 10, 2);
tvAreaFld = TableAddFieldFloat(unitAreaTbl, "Tv_Area", 10, 4);
tvPctFld = TableAddFieldFloat(unitAreaTbl, "Tv_Pct", 10, 2);
pCgrAreaFld = TableAddFieldFloat(unitAreaTbl, "pCgr_Area", 10, 4);
pCgrPctFld = TableAddFieldFloat(unitAreaTbl, "pCgr_Pct", 10, 2);
pCgsAreaFld = TableAddFieldFloat(unitAreaTbl, "pCgs_Area", 10, 4);
pCgsPctFld = TableAddFieldFloat(unitAreaTbl, "pCgs_Pct", 10, 2);
totUnitPctFld = TableAddFieldFloat(unitAreaTbl, "Total_Unit_Pct", 15, 2);
###################################################################
## loop through records in PolyToPoly table, and make corresponding
## records in new GraniteArea table
for i = 1 to basinInfoTbl.NumRecords
{
local array numeric elemList[1]; # array holding list of elements attached to current record
local numeric numElements; # number of elements attached to current record
local array numeric recNumbers[1]; # array of record numbers (1) to attach
local numeric j; # counter for element loop
local string sampID$ = BasinVectOut.poly.PolyToPoly[@i].REC_NO$;
local numeric totalAreaKm = BasinVectOut.poly.PolyToPoly[@i].TotalArea_sq_km;
# Add new record to GraniteArea table with values for first two fields
# from those in current record in PolyToPoly table
TableNewRecord(unitAreaTbl, sampID$, totalAreaKm);
}
## loop through records in UnitArea table and sum total contributing
## area for each basin (as check) and areas of each geologic unit in
## contributing area, then compute percentage for each unit
for i = 1 to unitAreaTbl.NumRecords
{
local numeric j, k, m, n;
local string sampID$ = BasinVectOut.poly.UnitArea[@i].REC_NO$;
local numeric recNum; # record number in PolyToPoly table
local numeric sumBasinArea; # running sum of polygon areas for basin
# numeric variables for summed area and percent of each rock unit in map area
local numeric cuArea, duArea, muArea, ouArea, qalArea, tgArea, tsArea, tvArea, pCgrArea, pCgsArea;
local numeric cuPct, duPct, muPct, ouPct, qalPct, tgPct, tsPct, tvPct, pCgrPct, pCgsPct;
local numeric totUnitPct;
# array to hold element numbers of polygons PolyToPoly record is attached to
local array numeric polyList[1];
local numeric numAttachedPolys; # number of polygons attached
# array to hold record numbers of PERCENTAGE table records attached to each polygon
local array numeric pctRecordList[1];
local numeric numPctRecords;
# call recursive function to get list of all upstream sample/basin IDs
getUpstreamIDs( sampID$ );
# loop through list of contributing basins to sum geologic unit areas
for j = 1 to idList.GetNumItems()
{
# get record number for basin's record in the PolyToPoly table
recNum = TableKeyFieldLookup(basinInfoTbl, "REC_NO", idList[j-1]);
# get list of polygon elements attached to that record
numAttachedPolys = TableGetRecordElementList(basinInfoTbl, recNum, polyList);
for k = 1 to numAttachedPolys # loop through polygons
{
sumBasinArea += BasinVectOut.poly[ polyList[k] ].POLYSTATS.Area;
# get list of record numbers of PERCENTAGE table records attached to polygon
numPctRecords = TableReadAttachment(percentTbl, polyList[k], pctRecordList);
for m = 1 to numPctRecords # loop through attached records to compute sums
{
n = pctRecordList[m];
if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "Cu") then
cuArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "Du") then
duArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "Mu") then
muArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "Ou") then
ouArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "Qal") then
qalArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "Tg") then
tgArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "Ts") then
tsArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "Tv") then
tvArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "pCgr") then
pCgrArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
else if ( BasinVectOut.poly.PERCENTAGE[@n].FORMATION$ == "pCgs") then
pCgsArea += BasinVectOut.poly.PERCENTAGE[@n].Area;
}
}
}
# use summed basin area and summed unit area to calculate percentage
cuPct = 100 * cuArea / sumBasinArea;
duPct = 100 * duArea / sumBasinArea;
muPct = 100 * muArea / sumBasinArea;
ouPct = 100 * ouArea / sumBasinArea;
qalPct = 100 * qalArea / sumBasinArea;
tgPct = 100 * tgArea / sumBasinArea;
tsPct = 100 * tsArea / sumBasinArea;
tvPct = 100 * tvArea / sumBasinArea;
pCgrPct = 100 * pCgrArea / sumBasinArea;
pCgsPct = 100 * pCgsArea / sumBasinArea;
# sum unit percentages for each basin as check
totUnitPct = round( (cuPct + duPct + muPct + ouPct + qalPct + tgPct + tsPct + tvPct + pCgrPct + pCgsPct ) );
# convert summed areas from square meters to square km
sumBasinArea = sumBasinArea / 1000000;
cuArea = cuArea / 1000000;
duArea = duArea / 1000000;
muArea = muArea / 1000000;
ouArea = ouArea / 1000000;
qalArea = qalArea / 1000000;
tgArea = tgArea / 1000000;
tsArea = tsArea / 1000000;
tvArea = tvArea / 1000000;
pCgrArea = pCgrArea / 1000000;
pCgsArea = pCgsArea / 1000000;
# write computed results to appropriate fields in UnitArea table
TableWriteField(unitAreaTbl, i, "CheckArea", sumBasinArea);
TableWriteField(unitAreaTbl, i, "Cu_Area", cuArea);
TableWriteField(unitAreaTbl, i, "Cu_Pct", cuPct);
TableWriteField(unitAreaTbl, i, "Du_Area", duArea);
TableWriteField(unitAreaTbl, i, "Du_Pct", duPct);
TableWriteField(unitAreaTbl, i, "Mu_Area", muArea);
TableWriteField(unitAreaTbl, i, "Mu_Pct", muPct);
TableWriteField(unitAreaTbl, i, "Ou_Area", ouArea);
TableWriteField(unitAreaTbl, i, "Ou_Pct", ouPct);
TableWriteField(unitAreaTbl, i, "Qal_Area", qalArea);
TableWriteField(unitAreaTbl, i, "Qal_Pct", qalPct);
TableWriteField(unitAreaTbl, i, "Tg_Area", tgArea);
TableWriteField(unitAreaTbl, i, "Tg_Pct", tgPct);
TableWriteField(unitAreaTbl, i, "Ts_Area", tsArea);
TableWriteField(unitAreaTbl, i, "Ts_Pct", tsPct);
TableWriteField(unitAreaTbl, i, "Tv_Area", tvArea);
TableWriteField(unitAreaTbl, i, "Tv_Pct", tvPct);
TableWriteField(unitAreaTbl, i, "pCgr_Area", pCgrArea);
TableWriteField(unitAreaTbl, i, "pCgr_Pct", pCgrPct);
TableWriteField(unitAreaTbl, i, "pCgs_Area", pCgsArea);
TableWriteField(unitAreaTbl, i, "pCgs_Pct", pCgsPct);
TableWriteField(unitAreaTbl, i, "Total_Unit_Pct", totUnitPct);
# clear all sum variables for next pass
sumBasinArea = 0;
cuArea = 0; duArea = 0; muArea = 0; ouArea = 0; qalArea = 0;
tgArea = 0; tsArea = 0; tvArea = 0; pCgrArea = 0; pCgsArea = 0; totUnitPct = 0;
# clear global stringlist of contributing basin IDs
idList.Clear();
}