#include "Flux_Manager_StormwaterDevice.h"

#include "Evaporation_StormwaterDevice.h"
#include "Infiltration_StormwaterDevice.h"
#include "Drainage_StormwaterDevice.h"
#include "Runoff_StormwaterDevice.h"
#include "Groundwater_StormwaterDevice.h"
#include "Leave_GI_Device.h"

//Calculate function organizes the inflows to the GI devices
void Flux_Manager_StormwaterDevice::Calculate(Inputs* input, CompactRagged* beC, 
	map<string, function<void(Inputs*, int) >>& functors, int DataDrawer_ID, int DataFolder_ID, int timeStep) {

	//Time_PeriodSincePavementRegenerated_hr is increased by Ratio_Hour_to_Second * SimulationTimeStep_Duration_sec[timeStep]
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Time_PeriodSincePavementRegenerated_hr") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Time_PeriodSincePavementRegenerated_hr") +	Ratio_Hour_to_Second * input->SimulationTimeStep_Duration_sec[timeStep];
	//If Precip_mpdt is greater than Flux_GI_Minimum_m_p_s (converted to per time step) then reset Time_PrecipitationEnded_hr to 0
	if (input->Precip_mpdt[timeStep] > (Flux_GI_Minimum_m_p_s * input->SimulationTimeStep_Duration_sec[timeStep])) {
		//Time_PrecipitationEnded_hr (hr) reset to 0 when precipitation occurs that is > Flux_GI_Minimum_m_p_s
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Time_PrecipitationEnded_hr") = 0.0;
	}
	//Else Precip_mpdt was less than Flux_GI_Minimum_m_p_s (adjusted to per time step) and Time_PrecipitationEnded_hr is increased
	else {
		//Time_PrecipitationEnded_hr is increased by Ratio_Hour_to_Second * SimulationTimeStep_Duration_sec[timeStep]
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Time_PrecipitationEnded_hr") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Time_PrecipitationEnded_hr") + Ratio_Hour_to_Second * input->SimulationTimeStep_Duration_sec[timeStep];
	}

	//If Flag_Exfiltration_to_Catchment equals 1, then GI Type has exfiltration to catchment and allows for groundwater upwelling
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Flag_Exfiltration_to_Catchment")== 1) {
		//Groundwater_StormwaterDevice::Saturation_by_WaterTable function will update layer maximum storage if groundwater occupies layer
		Groundwater_StormwaterDevice::Saturation_by_WaterTable(input, beC, DataDrawer_ID, DataFolder_ID, timeStep);
	}

	//Flux_GI_Surface_m3 (m3) reset to zero before computing flux for time step
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Surface_m3") = 0.0;
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Pavement_m3") = 0.0;
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Soil_m3") = 0.0;
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Vault_m3") = 0.0;
	//Flux_GI_SurfaceDepression_m3 (m3) introduced to manage depression storage in GI unit
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_SurfaceDepression_m3") = 0.0;

	//Storage_GI_Surface_TS_Prior_m3 (m3) takes value of storage from prior time step Storage_GI_Surface_m3
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_TS_Prior_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3");
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_TS_Prior_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_m3");
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_TS_Prior_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_m3");
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_TS_Prior_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3");
	//Storage_GI_SurfaceDepression_TS_Prior_m3 (m3) and Storage_GI_SurfaceDepression_m3 (m3) introduced to manage depression storage in GI unit
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_TS_Prior_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_m3");

	//GI_Flux_Layer_Sequencer function called to coordinate flux rates for all GI Types; output is Flux_GI_Layer_m3 (m3)
	//Note: GI Types are Bioretention, InfilTrench, PermeablePavement, RainGarden, Swale, GreenRoof, RainBarrel, RoofDisconnect
	Flux_Manager_StormwaterDevice::GI_Flux_Layer_Sequencer(input, beC, functors, DataDrawer_ID, DataFolder_ID, timeStep);

	//Storage_GI_Surface_m3 (m3) is sum of Storage_GI_Surface_TS_Prior_m3 (m3) and Flux_GI_Surface_m3 (m3), old storage plus new flux
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_TS_Prior_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Surface_m3");
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_TS_Prior_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Pavement_m3");
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_TS_Prior_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Soil_m3");
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_TS_Prior_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Vault_m3");
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_TS_Prior_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_SurfaceDepression_m3");

	//Control for negative values by taking maximum of Storage_GI_Layer_m3 and zero
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3") = MAX(beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3"), 0);
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_m3") = MAX(beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_m3"), 0);
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_m3") = MAX(beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_m3"), 0);
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3") = MAX(beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3"), 0);
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_m3") = MAX(beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_m3"), 0);
	//Storage_GI_SurfaceDepression_m3 (m3) is the minimum of Storage_GI_SurfaceDepression_m3 and Storage_GI_SurfaceDepression_Max_m3 (m3)
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_m3") = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_m3"), beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_SurfaceDepression_Max_m3"));

	//If Storage_GI_Surface_m3 > Storage_GI_Surface_Max_m3 then remove excess water
	//Note: Emergency runoff occurs after Flux_Manager_StormwaterDevice::GI_Flux_Layer_Sequencer function, and infiltration can occur before runoff
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3") >= beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_Max_m3")) {
		//Runoff_Surface_BermCrest_m3 (m3) from Runoff_StormwaterDevice::Runoff_Surface_Emergency function, surface emergency overflow over berm top 
		//Note: Runoff_StormwaterDevice::Runoff_Surface_Emergency function is used to check if water depth overtops GI maximum surface storage height
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_BermCrest_m3") = Runoff_StormwaterDevice::Runoff_Surface_Emergency(beC, DataDrawer_ID, DataFolder_ID);

		//Equations to track portion of runoff volume attributed to each land cover type
		//Runoff_Pervious_m3 (m3) is portion of Runoff_Surface_m3 (m3) from pervious cover, determined by multiplication with PerviousCover_frac (fraction)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Pervious_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Pervious_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_BermCrest_m3") * beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousCover_frac");
		//Runoff_Impervious_m3 (m3) is portion of Runoff_Surface_m3 (m3) from impervious cover, determined by multiplication with ImperviousCover_frac (fraction)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Impervious_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Impervious_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_BermCrest_m3") * beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_frac");
		//Runoff_Water_m3 (m3) is portion of Runoff_Surface_m3 (m3) from water cover, determined by multiplication with WaterCover_noTreeCanopy_frac (fraction)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Water_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Water_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_BermCrest_m3") * beC->by_key(DataDrawer_ID, DataFolder_ID, "WaterCover_noTreeCanopy_frac");

		//Runoff_Surface_m3 (m) increased by Runoff_Surface_BermCrest_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_BermCrest_m3");
		//Control for less than zero condition
		if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") < 0.0) { beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") = 0.0; }
	}

	//Depth_GI_Surface_m (m) is computed to manage head based runoff

	//If Flag_Exfiltration_to_Catchment equals 1, then GI Type has exfiltration to catchment and allows for groundwater upwelling
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Flag_Exfiltration_to_Catchment")== 1) {
		//Call Drainage_StormwaterDevice::Drainage_VadoseZone to determine drainage to vadose zone
		Drainage_StormwaterDevice::Drainage_VadoseZone(input, beC, DataDrawer_ID, DataFolder_ID, timeStep);
		//Call Groundwater_StormwaterDevice::Groundwater_Mounding to determine temporary mounding of groundwater below GI device
		Groundwater_StormwaterDevice::Groundwater_Mounding(input, beC, DataDrawer_ID, DataFolder_ID, timeStep);
	}
	//Call Leave_GI_Device::CollectVariables function to organize GI storage and flux variables
	Leave_GI_Device::CollectVariables(input, beC, DataDrawer_ID, DataFolder_ID, timeStep);
}

//GI_Flux_Layer_Sequencer function coordinates flux rates for all GI Types
//Note: GI Types are Bioretention, InfilTrench, PermeablePavement, RainGarden, Swale, GreenRoof, RainBarrel, RoofDisconnect
void Flux_Manager_StormwaterDevice::GI_Flux_Layer_Sequencer(Inputs* input, CompactRagged* beC,
	map<string, function<void(Inputs*, int) >>& functors, int DataDrawer_ID, int DataFolder_ID, int timeStep)
{
	//Storage_GI_Surface_m3 (m3) defined as Storage_GI_Surface_m3 (m3)
	double Storage_GI_Surface_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3");
	//Storage_GI_Pavement_m3 (m3) defined as Storage_GI_Pavement_m3 (m3)
	double Storage_GI_Pavement_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_m3");
	//Storage_GI_Soil_m3 (m3) defined as Storage_GI_Soil_m3 (m3)
	double Storage_GI_Soil_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_m3");
	//Storage_GI_Vault_m3 (m3) defined as Storage_GI_Layer_m3 (m3)
	double Storage_GI_Vault_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3");

	//Evaporation_StormwaterDevice::GI_RateOfEvaporation function will obtain Evaporation_Surface_m3 (m3), EvapoTrans_Pavement_m3 (m3), EvapoTrans_Soil_m3 (m3), EvapoTrans_Vault_m3 (m3)
	Evaporation_StormwaterDevice::GI_RateOfEvaporation(input, beC, functors, DataDrawer_ID, DataFolder_ID, timeStep);

	//Pavement_HydraulicConductivity_mph (m/h) defined by Drainage_StormwaterDevice::Percolation_Pavement function before calling Infiltration_StormwaterDevice::GI_RateOfInfiltration
	Drainage_StormwaterDevice::Percolation_Pavement(input, beC, DataDrawer_ID, DataFolder_ID, timeStep);

	//Infiltration_StormwaterDevice::GI_RateOfInfiltration function will obtain Infiltration_Surface_m3 (m3)
	Infiltration_StormwaterDevice::GI_RateOfInfiltration(input, beC, functors, DataDrawer_ID, DataFolder_ID, timeStep);

	//Percolation_Soil_m3 (m3) determined by Drainage_StormwaterDevice::Percolation_Soil function
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3") = Drainage_StormwaterDevice::Percolation_Soil(input, beC, DataDrawer_ID, DataFolder_ID, timeStep);

	//Exfiltration_m3 (m3) determined by Drainage_StormwaterDevice::Exfiltration_Vault function
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3") = Drainage_StormwaterDevice::Exfiltration_Vault(input, beC, DataDrawer_ID, DataFolder_ID, timeStep);

	//If Time_PrecipitationEnded_hr > Vault_Outlet_Delay_hr then allow Runoff_Vault_m3
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Time_PrecipitationEnded_hr") >= beC->by_key(DataDrawer_ID, DataFolder_ID, "Vault_Outlet_Delay_hr")) {
		//Runoff_Vault_m3 (m3) defined by Runoff_StormwaterDevice::Runoff_Vault_Drain function
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3") = Runoff_StormwaterDevice::Runoff_Vault_Drain(beC, DataDrawer_ID, DataFolder_ID, timeStep);
	}

	//Runoff_Surface_m3 (m3) determined by Runoff_StormwaterDevice::Runoff_Surface_Outlet function
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") = Runoff_StormwaterDevice::Runoff_Surface_Outlet(input, beC, DataDrawer_ID, DataFolder_ID, timeStep);

	//Equations to track portion of runoff volume attributed to each land cover type
	//Runoff_Pervious_m3 (m3) is portion of Runoff_Surface_m3 (m3) from pervious cover, determined by multiplication with PerviousCover_frac (fraction)
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Pervious_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") * beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousCover_frac");
	//Runoff_Impervious_m3 (m3) is portion of Runoff_Surface_m3 (m3) from impervious cover, determined by multiplication with ImperviousCover_frac (fraction)
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Impervious_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") * beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_frac");
	//Runoff_Impervious_m3 (m3) is increased by Runoff_Impervious_to_Outlet_m3 (m3), generated in Inflow_StormwaterDevice by Flux_to_ImperviousArea_Rain_SnowMelt_Irrigation_m on DCIA
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Impervious_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Impervious_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Impervious_to_Outlet_m3");
	//Runoff_Water_m3 (m3) is portion of Runoff_Surface_m3 (m3) from water cover, determined by multiplication with WaterCover_noTreeCanopy_frac (fraction)
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Water_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") * beC->by_key(DataDrawer_ID, DataFolder_ID, "WaterCover_noTreeCanopy_frac");

	//Runoff_Surface_m3 (m3) is increased by Runoff_Impervious_to_Outlet_m3 (m3) from DCIA
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Impervious_to_Outlet_m3");

	//GI_Flux_Storage_Balancer function will balance the above flux rates to conserve water between inflows, outflows, and storage
	GI_Flux_Storage_Balancer(beC, DataDrawer_ID, DataFolder_ID, timeStep);

	//Flux_GI_Surface_m3 (m3) as balance of inflow and outflow
	//Note: inflow = Flux_to_GI_Precipitation_m3 (m3) + Flux_BulkArea_to_GI_Runon_m3 (m3) + Flux_GI_to_GI_Runon_m3 (m3)
	//Note: outflow = EvapoTrans_Surface_m3 (m3) + Infiltration_Surface_m3 (m3) + Runoff_Surface_m3 (m3)ation limited to pervious areas
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Surface_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_to_GI_Precipitation_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_BulkArea_to_GI_Runon_m3") +
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_to_GI_Runon_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") - 
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3"));
	
	//If Storage_GI_Surface_Max_m3 > 0 then enter for division
	//Note: Depth may not be stored in a rectangular GI unit due to Surface_SideSlope_HtoV_mpm, and storage volume ratios handle this ambiguity
	//Note: If Storage_GI_Surface_Max_m3 = 0, then Surface_SideSlope_HtoV_mpm, Surface_Berm_Height_m, Surface_Berm_Height_m, or Surface_Porosity_m3pm3 = 0
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_Max_m3") > 0) {
		//Flux_GI_SurfaceDepression_m3 (m3) as balance of inflow and outflow for surface depression storage
		//Note: inflow = Flux_to_GI_Precipitation_m3 (m3) + (Flux_BulkArea_to_GI_Runon_m3 + Fux_GI_to_GI_Runon_m3) (m3) * (Storage_GI_Surface_m3 / Storage_GI_Surface_Max_m3) (m3)
		//Note: outflow = EvapoTrans_Surface_m3 (m3) + Infiltration_Surface_m3 (m3) * Area_GI_Unit_Pervious_m2 / Area_GI_Unit_m2 (m2)
		//Note: EvapoTrans_Surface_m3 (m3) includes pervious, impervious, and water terms based on fractional coverage
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_SurfaceDepression_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_to_GI_Precipitation_m3") + ((beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_BulkArea_to_GI_Runon_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_to_GI_Runon_m3")) * (beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3") / beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_Max_m3"))) - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") * (beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_GI_Unit_Pervious_m2") / beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_GI_Unit_m2")));
	}
	//Else Storage_GI_Surface_Max_m3 <= 0 and determine Flux_GI_SurfaceDepression_m3 (m3) using Area_GI_Unit_m2 (m2)
	else {
		//Flux_GI_SurfaceDepression_m3 (m3) as balance of inflow and outflow for surface depression storage
		//Note: inflow = Flux_to_GI_Precipitation_m3 (m3) + (Flux_BulkArea_to_GI_Runon_m3 + Fux_GI_to_GI_Runon_m3) (m3)
		//Note: outflow = EvapoTrans_Surface_m3 (m3) + Infiltration_Surface_m3 (m3) * Area_GI_Unit_Pervious_m2 / Area_GI_Unit_m2 (m2)
		//Note: EvapoTrans_Surface_m3 (m3) includes pervious, impervious, and water terms based on fractional coverage
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_SurfaceDepression_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_to_GI_Precipitation_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_BulkArea_to_GI_Runon_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_to_GI_Runon_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") * (beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_GI_Unit_Pervious_m2") / beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_GI_Unit_m2")));
	}
	//If Pavement_Thickness_m (m) <= zero then set Flux_GI_Pavement_m3 to zero
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Pavement_Thickness_m") > Constant_1E_negative10 && beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Thickness_m") > Constant_1E_negative10) {
		//Flux_GI_Pavement_m3 (m3) as balance of inflow and outflow
		//Note: inflow = Infiltration_Surface_m3 (m3), outflow = EvapoTrans_Pavement_m3 (m3) + Percolation_Pavement_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Pavement_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Pavement_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3"));
		//Flux_GI_Soil_m3 (m3) as balance of inflow and outflow
		//Note: inflow = Percolation_Pavement_m3 (m3), outflow = EvapoTrans_Soil_m3 (m3) + Exfiltration_m3 (m3) + Percolation_Soil_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Soil_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Soil_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3"));
		//Flux_GI_Vault_m3 (m3) as balance of inflow and outflow, using Percolation_Potential_m3 in place of Percolation_Soil_m3 or Percolation_Pavement_m3
		//Note: inflow = Percolation_Potential_m3 (m3), outflow = EvapoTrans_Vault_m3 (m3) + Exfiltration_m3 (m3) + Runoff_Vault_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Vault_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3"));
	}
	else if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Pavement_Thickness_m") > Constant_1E_negative10) {
		//Flux_GI_Pavement_m3 (m3) as balance of inflow and outflow
		//Note: inflow = Infiltration_Surface_m3 (m3), outflow = EvapoTrans_Pavement_m3 (m3) + Percolation_Pavement_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Pavement_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Pavement_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3"));
		//Flux_GI_Vault_m3 (m3) as balance of inflow and outflow, using Percolation_Potential_m3 in place of Percolation_Soil_m3 or Percolation_Pavement_m3
		//Note: inflow = Percolation_Potential_m3 (m3), outflow = EvapoTrans_Vault_m3 (m3) + Exfiltration_m3 (m3) + Runoff_Vault_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Vault_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3"));
	}
	else if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Thickness_m") > Constant_1E_negative10) {
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Pavement_m3") = 0.0;
		//Flux_GI_Soil_m3 (m3) as balance of inflow and outflow
		//Note: inflow = Infiltration_Surface_m3 (m3), outflow = EvapoTrans_Soil_m3 (m3) + Percolation_Soil_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Soil_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Soil_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3"));
		//Flux_GI_Vault_m3 (m3) as balance of inflow and outflow
		//Note: inflow = Percolation_Soil_m3 (m3), outflow = EvapoTrans_Vault_m3 (m3) + Exfiltration_m3 (m3) + Runoff_Vault_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Vault_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3"));
	}
	else {
		//Flux_GI_Vault_m3 (m3) as balance of inflow and outflow
		//Note: inflow = Percolation_Soil_m3 (m3), outflow = EvapoTrans_Vault_m3 (m3) + Exfiltration_m3 (m3) + Runoff_Vault_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Vault_m3") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3"));
	}

	//If Pavement_Thickness_m (m) <= zero then set Flux_GI_Pavement_m3 (m3) to zero
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Pavement_Thickness_m") <= Constant_1E_negative10) { beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Pavement_m3") = 0.0; }
	//If Soil_Thickness_m (m) <= zero then set Flux_GI_Soil_m3 (m3) to zero
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Thickness_m") <= Constant_1E_negative10) { beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Soil_m3") = 0.0; }
	//If Vault_Thickness_m (m) <= zero then set Flux_GI_Vault_m3 (m3) to zero
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Vault_Thickness_m") <= Constant_1E_negative10) { beC->by_key(DataDrawer_ID, DataFolder_ID, "Flux_GI_Vault_m3") = 0.0; }

}


//GI_Flux_Storage_Balancer function finds vertical fluxes for GI unit, balancing inputs, outputs, and storage layers
//Note: GI_Flux_Storage_Balancer balances inputs, outputs, and storage layer by moving from GI unit bottom to top
void Flux_Manager_StormwaterDevice::GI_Flux_Storage_Balancer(CompactRagged* beC, int DataDrawer_ID, int DataFolder_ID, int timeStep)
{
	double Potential_Flux_m3 = 0.0;
	double Potential_Storage_m3 = 0.0;
	double Infiltration_TS_Start_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3");
	double Infiltration_TS_Stop_m3 = 0.0;

	//If Vault_Thickness_m (m) > Constant_1E_negative10 then
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Vault_Thickness_m") > Constant_1E_negative10) {
		//Potential_Storage_m3 (m3) is available water, Storage_GI_Vault_m3 (m3) - EvapoTrans_Vault_m3 (m3)
		Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3");
		//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
		Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
		//Exfiltration_m3 (m3) is minimum of Exfiltration_m3 (m3) and Potential_Storage_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3") = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3"), Potential_Storage_m3);
		//If Soil_Thickness_m <= Constant_1E_negative10 && Pavement_Thickness_m <= Constant_1E_negative10 then 
		//Note: ... Surface Layer above Storage Layer
		if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Thickness_m") <= Constant_1E_negative10 && beC->by_key(DataDrawer_ID, DataFolder_ID, "Pavement_Thickness_m") <= Constant_1E_negative10) {
			//Potential_Storage_m3 (m3) is available water, Storage_GI_Surface_m3 (m3) minus Evaporation_Surface_m3 and Runoff_Surface_m3(m3)
			Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Surface_m3") 
				- beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3");
			//If Type = RainBarrel then 
			if (beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RainBarrel") {
				//Potential_Storage_m3 (m3) equals Infiltration_Surface_m3 (M3), bypassing the constraint of Surface Layer available water 
				Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3");
			}
			//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
			Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
			//Potential_Flux_m3 (m3) is minimum of Infiltration_Surface_m3 (m3) and Potential_Storage_m3 (m3)
			Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3"), Potential_Storage_m3);
			//Potential_Storage_m3 (m3) is available storage, Storage_GI_Vault_Max_m3 (m3) minus Storage_GI_Vault_m3 (m3), plus 
			//Note: EvapoTrans_Vault_m3 (m3), Runoff_Vault_m3 (m3), Exfiltration_m3 (m3)
			Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_Max_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3") +
				beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3");
			//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
			Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
			//Potential_Flux_m3 (m3) is minimum of Potential_Flux_m3 (m3) and Potential_Storage_m3 (m3)
			Potential_Flux_m3 = MIN(Potential_Flux_m3, Potential_Storage_m3);
			//Infiltration_Surface_m3 (m3) is Potential_Flux_m3 (m3)
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") = Potential_Flux_m3;
		}
	}
	//If Runoff_Vault_m3 (m) > 0 then Drainage Pipe flux possible
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3") > 0) {
		//Potential_Storage_m3 (m3) is available water, Storage_GI_Vault_m3 (m3) minus Threshold_VaultDrain_m3, EvapoTrans_Vault_m3, Exfiltration_m3 (m3)
		Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Threshold_VaultDrain_m3") -
			beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3");
		//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
		Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
		//Potential_Flux_m3 (m3) is minimum of Runoff_Vault_m3 (m3) and Potential_Storage_m3 (m3)
		Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3"), Potential_Storage_m3);
		//Runoff_Vault_m3 is Potential_Flux_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3") = Potential_Flux_m3;
	}
	//If Soil_Thickness_m (m) > Constant_1E_negative10 then
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Thickness_m") > Constant_1E_negative10) {
		//Potential_Storage_m3 (m3) is available water, Storage_GI_Soil_m3 (m3) - EvapoTrans_Soil_m3 (m3)
		Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Soil_m3");
		//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
		Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
		//Percolation_Soil_m3 (m3) is minimum of Percolation_Soil_m3 (m3) and Potential_Storage_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3") = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3"), Potential_Storage_m3);
		//If Vault_Thickness_m (m) > Constant_1E_negative10 then Soil Layer above Storage Layer
		if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Vault_Thickness_m") > Constant_1E_negative10) {
			//Potential_Storage_m3 (m3) is available storage, Storage_GI_Vault_Max_m3 (m3) minus Storage_GI_Vault_m3 (m3), plus 
			//Note: EvapoTrans_Vault_m3 (m3), Runoff_Vault_m3 (m3), Exfiltration_m3 (m3)
			Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_Max_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3") +
				beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3");
			//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
			Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
			//Potential_Flux_m3 (m3) is minimum of Percolation_Soil_m3 (m3) and Potential_Storage_m3 (m3)
			Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3"), Potential_Storage_m3);
		}
		//Else Vault_Thickness_m (m) <= 0 then Soil Layer above Native Soils
		else {
			//Potential_Flux_m3 (m3) is minimum of Percolation_Soil_m3 (m3) and Exfiltration_m3 (m3)
			Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3"), beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3"));
		}
		//Percolation_Soil_m3 (m3) is Potential_Flux_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3") = Potential_Flux_m3;
		//If Vault_Thickness_m <= Constant_1E_negative10 then Soil Layer above Native Soil
		if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Vault_Thickness_m") <= Constant_1E_negative10) {
			//Exfiltration_m3  (m3) is Potential_Flux_m3 (m3)
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3") = Potential_Flux_m3;
		}
		//If Pavement_Thickness_m <= Constant_1E_negative10 then Surface Layer above Soil Layer
		if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Pavement_Thickness_m") <= Constant_1E_negative10) {
			//Potential_Storage_m3 (m3) is available water, Storage_GI_Surface_m3 (m3) minus Evaporation_Surface_m3 and Runoff_Surface_m3(m3)
			Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Surface_m3") - 
				beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3");
			//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
			Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
			//Potential_Flux_m3 (m3) is minimum of Infiltration_Surface_m3 (m3) and Potential_Storage_m3 (m3)
			Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3"), Potential_Storage_m3);
			//Potential_Storage_m3 (m3) is available storage, Storage_GI_Soil_Max_m3 (m3) minus Storage_GI_Soil_m3 (m3) plus 
			//Note: EvapoTrans_Soil_m3 (m3), Percolation_Soil_m3 (m3)
			Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_Max_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_m3") +
				beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Soil_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3");
			//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
			Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
			//Potential_Flux_m3 (m3) is minimum of Potential_Flux_m3 (m3) and Potential_Storage_m3 (m3)
			Potential_Flux_m3 = MIN(Potential_Flux_m3, Potential_Storage_m3);
			//Infiltration_Surface_m3 (m3) is Potential_Flux_m3
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") = Potential_Flux_m3;
		}
	}
	//If Pavement_Thickness_m (m) > Constant_1E_negative10 then
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Pavement_Thickness_m") > Constant_1E_negative10) {
		//Potential_Storage_m3 (m3) is available water, Storage_GI_Pavement_m3 (m3) - EvapoTrans_Pavement_m3 (m3)
		Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Pavement_m3");
		//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
		Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
		//Percolation_Pavement_m3 (m3) is minimum of Percolation_Pavement_m3 (m3) and Potential_Storage_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3") = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3"), Potential_Storage_m3);
		//If Soil_Thickness_m (m) > Constant_1E_negative10 then Pavement Layer above Soil Layer
		if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Thickness_m") > Constant_1E_negative10) {
			//Potential_Storage_m3 (m3) is available storage, Storage_GI_Soil_Max_m3 (m3) minus Storage_GI_Soil_m3 (m3) plus 
			//Note: EvapoTrans_Soil_m3 (m3), Percolation_Soil_m3 (m3)
			Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_Max_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Soil_m3") +
				beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Soil_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Soil_m3");
			//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
			Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
			//Potential_Flux_m3 (m3) is minimum of Percolation_Pavement_m3 (m3) and Potential_Storage_m3 (m3)
			Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3"), Potential_Storage_m3);
		}
		//Else If Soil_Thickness_m <= Constant_1E_negative10 && Vault_Thickness_m (m) > Constant_1E_negative10 then 
		//Note: ... Pavement Layer above Storage Layer
		else if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Thickness_m") <= Constant_1E_negative10 && beC->by_key(DataDrawer_ID, DataFolder_ID, "Vault_Thickness_m") > Constant_1E_negative10) {
			//Potential_Storage_m3 (m3) is available storage, Storage_GI_Vault_Max_m3 (m3) minus Storage_GI_Vault_m3 (m3), plus 
			//Note: EvapoTrans_Vault_m3 (m3), Runoff_Vault_m3 (m3), Exfiltration_m3 (m3)
			Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_Max_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Vault_m3") +
				beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Vault_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Vault_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3");
			//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
			Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
			//Potential_Flux_m3 (m3) is minimum of Percolation_Pavement_m3 (m3) and Potential_Storage_m3 (m3)
			Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3"), Potential_Storage_m3);
		}
		//Else Vault_Thickness_m (m) <= 0 then Pavement Layer above Native Soils
		else {
			//Potential_Flux_m3 (m3) is minimum of Percolation_Pavement_m3 (m3) and Exfiltration_m3 (m3)
			Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3"), beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3"));
		}
		//Percolation_Pavement_m3 (m3) is Potential_Flux_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3") = Potential_Flux_m3;
		//If Vault_Thickness_m <= Constant_1E_negative10 then Pavement Layer above Native Soil
		if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Vault_Thickness_m") <= Constant_1E_negative10) {
			//Exfiltration_m3  (m3) is Potential_Flux_m3 (m3)
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Exfiltration_m3") = Potential_Flux_m3;
		}
		//Surface Layer is above Pavement Layer 
		//Potential_Storage_m3 (m3) is available water, Storage_GI_Surface_m3 (m3) minus Evaporation_Surface_m3 and Runoff_Surface_m3(m3)
		Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Surface_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Surface_m3") - 
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Surface_m3");
		//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
		Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
		//Potential_Flux_m3 (m3) is minimum of Infiltration_Surface_m3 (m3) and Potential_Storage_m3 (m3)
		Potential_Flux_m3 = MIN(beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3"), Potential_Storage_m3);
		//Potential_Storage_m3 (m3) is available storage, Storage_GI_Pavement_Max_m3 (m3) minus Storage_GI_Pavement_m3 (m3) plus 
		//Note: EvapoTrans_Pavement_m3 (m3), Percolation_Pavement_m3 (m3)
		Potential_Storage_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_Max_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_GI_Pavement_m3") +
			beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapoTrans_Pavement_m3") + beC->by_key(DataDrawer_ID, DataFolder_ID, "Percolation_Pavement_m3");
		//Potential_Storage_m3 (m3) is maximum of Potential_Storage_m3 (m3) and 0
		Potential_Storage_m3 = MAX(Potential_Storage_m3, 0);
		//Potential_Flux_m3 (m3) is minimum of Potential_Flux_m3 (m3) and Potential_Storage_m3 (m3)
		Potential_Flux_m3 = MIN(Potential_Flux_m3, Potential_Storage_m3);
		//Infiltration_Surface_m3 (m3) is Potential_Flux_m3 (m3)
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3") = Potential_Flux_m3;
	}

	//Rudimentary estimator of fraction of pervious surface runoff generated by infiltration excess vs saturation excess
	Infiltration_TS_Stop_m3 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Infiltration_Surface_m3");
	//If Infiltration_TS_Start_m3 (m3) greater than zero and Infiltration_TS_Stop_m3 (m3) then
	if (Infiltration_TS_Start_m3 > 0 && Infiltration_TS_Start_m3 > Infiltration_TS_Stop_m3) {
		//Ratio_RunoffInfilExcess_to_RunoffPervious (fraction) is ratio of Runoff_InfilExcess to Runoff_Pervious, where Runoff_Pervious = Runoff_InfilExcess + Runoff_SatExcess
		//Note Estimation is simply based on this quotient, Ratio_RunoffInfilExcess_to_RunoffPervious = (Infiltration_TS_Start_m3 - Infiltration_TS_Stop_m3) / Infiltration_TS_Start_m3 
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Ratio_RunoffInfilExcess_to_RunoffPervious") = ((Infiltration_TS_Start_m3 - Infiltration_TS_Stop_m3) / Infiltration_TS_Start_m3);
	}
	//Else Infiltration_TS_Start_m3 (m3) less than or equal to zero and Infiltration_TS_Stop_m3 (m3) then
	else {
		//Ratio_RunoffInfilExcess_to_RunoffPervious (fraction) is zero
		beC->by_key(DataDrawer_ID, DataFolder_ID, "Ratio_RunoffInfilExcess_to_RunoffPervious") = 0;
	}

	//Note: Consider refactor to use input to read Flag_GI_SVAT read from HydroPlusConfig.xml for additional functionality
	bool Flag_GI_SVAT = 0;
	//If Flag_GI_SVAT equals 1 then enter and Runoff_Pervious_m3 > Runoff_SatExcess_m3 then enter
	if (Flag_GI_SVAT == 1) {
		//Note: Consider refactor to compute Runoff_SatExcess_m3 using input->RepoDict["Groundwater_surficial_frac"], not just infiltration
		if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Pervious_m3") > beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_SatExcess_m3")) {
			//Runoff_InfilExcess_m3 (m3) is remainder of Runoff_Pervious_m3 (m3) - Runoff_SatExcess_m3 (m3)
			//Note: Runoff_SatExcess_m3 (m3) is product of Groundwater_surficial_frac (frac) and sum of all inflow, Flux_to_GI_Precipitation_m3, ...
			//Note: ... Flux_BulkArea_to_GI_Runon_m3, and Flux_GI_to_GI_Runon_m3
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_InfilExcess_m3") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Pervious_m3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_SatExcess_m3");
			//Ratio_RunoffInfilExcess_to_RunoffPervious (fraction) is ratio of Runoff_InfilExcess_m3 (m3) to Runoff_Pervious_m3 (m3)
			//Note: Runoff_Pervious_m3 (m3) = Runoff_InfilExcess_m3 (m3) + Runoff_SatExcess_m3 (m3)
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Ratio_RunoffInfilExcess_to_RunoffPervious") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_InfilExcess_m3") / beC->by_key(DataDrawer_ID, DataFolder_ID, "Runoff_Pervious_m3");
		}
		//Else Ratio_RunoffInfilExcess_to_RunoffPervious is zero, and in RunoffSummation.cpp Runoff_SatExcess_m3 is all runoff
		else {
			//Ratio_RunoffInfilExcess_to_RunoffPervious goes to 0
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Ratio_RunoffInfilExcess_to_RunoffPervious") = 0;
		}
	}
}
