#include "BuildDataOrganizer.h"

void BuildDataOrganizer::BuildDataOrganizer_Manager(DataOrganizer* organizer, Inputs* input, CompactRagged* beC, string Directory_Input_CLArg)
{
	//If Model is SpatialTemperatureHydro then
	if (input->SimulationStringParams["Model_Selection"] == "SpatialTemperatureHydro") {
		//BuildDataOrganizer_Spatial function is called
		BuildDataOrganizer_Spatial(organizer, input, beC, Directory_Input_CLArg);
	}
	//Else if Model is StatisticalHydro then
	else if (input->SimulationStringParams["Model_Selection"] == "StatisticalHydro"|| input->SimulationStringParams["Model_Selection"] == "SpatialBufferwGI") {

		//BuildDataOrganizer_Statistical function is called
		BuildDataOrganizer_Statistical(organizer, input, beC, Directory_Input_CLArg);
	}
	//If Flag_GI_Simulated equals 1 then GI simulated and compute variable averages
	if (input->RepoDict["Flag_GI_Simulated"] == 1) {
		//Prepare_GI_PollutantRemoval function computes GI variable weighted averages
		Prepare_GI_PollutantRemoval(organizer, input, beC);
	}
}

//BuildDataOrganizer_Spatial function called for Model = SpatialTemperatureHydro
//Note: For model = SpatialTemperatureHydro, DataDrawer_ID has maximum = maxRows * maxCols, and DataFolder_ID typically has maximum = 1
void BuildDataOrganizer::BuildDataOrganizer_Spatial(DataOrganizer* organizer, Inputs* input, CompactRagged* beC, string Directory_Input_CLArg)
{
	//FolderType_List.clear before loop
	input->FolderType_List.clear();
	//RepoVecDict["Catchment_Type_Area_m2"].clear() before loop
	//Note: Model SpatialTemperatureHydro will sum catchment area into Catchment_Type_Area_m2
	input->RepoVecDict["Catchment_Type_Area_m2"].clear();
	//Folder_Type_ID will track Folder as BulkArea of GreenInfrastructure
	int Folder_Type_ID = 0;
	//FolderType_List.push_back(Folder_Type_ID) is given 1 item for SpatialTemperatureHydro
	input->FolderType_List.push_back(Folder_Type_ID);
	//RepoVecDict["Catchment_Type_Area_m2"].push_back(0.0); sized for 1 Folder_Type_ID
	input->RepoVecDict["Catchment_Type_Area_m2"].push_back(0.0);
	//initialize placeholder for DataDrawer_ID counter, set to zero, used in Catchment_CoverData_FolderType function
	int DataDrawer_ID = 0;
	//input->RepoDict["Catchment_PerviousArea_AffectingStorageDeficit_m2"] reset to zero
	input->RepoDict["Catchment_PerviousArea_AffectingStorageDeficit_m2"] = 0;
	//Flag_GI_Simulated flag set = 0, ensuring no transfer of water between GI and BulkArea
	//Note: SpatialTemeperatureHydro model may be refactored to support GI, and this flag could be set to 1
	input->RepoDict["Flag_GI_Simulated"] = 0;
	//Folder StorageDeficit_VadoseZone_m variable set to the initial average soil moisture deficit, AveSMD (m), which regulates TOPMODEL theory
	input->RepoDict["StorageDeficit_VadoseZone_m"] = input->AveSMD;
	//initialize the  DataFolder_ID to be 0
	int DataFolder_ID = 0;

	//Error handling for CoolAir simulations
	//maxRows and maxCols set to 400 based on typical RAM limitations for CoolAir runs
	double maxRows = 500; double maxCols = 500;
	if (int(input->SimulationNumericalParams["NumberOfLocations"]) > maxRows * maxCols) {
		cout << endl << "Please note: Input map Rows and Columns exceed 500 x 500 and may overwhelm the computer RAM." << endl;
		cout << "Explanation: If RAM is exceeded, then the simulation will likely hang when creating DataOrganizer folders." << endl;
		cout << "Solution: If simulation hangs, then use smaller map arrays, either with coarser pixels or with post-run mosaics." << endl;
	}

	//For (int MapPixel_ID = 0; MapPixel_ID < input->SimulationNumericalParams["NumberOfLocations"]; ++MapPixel_ID) 
	//Note: NumberOfLocations is number of map pixels in dem.asc, equal to nRows * nCols for SpatialTemperatureHydro; 1 for StatisticalHydro 
	for (int MapPixel_ID = 0; MapPixel_ID < input->SimulationNumericalParams["NumberOfLocations"]; ++MapPixel_ID) {

		//int Folder_count = beC->folders_in_drawer(beC, MapPixel_ID);
		int Folder_count = beC->folders_in_drawer(beC, MapPixel_ID);
		//If organizer->DataDrawers[MapPixel_ID].empty() then a NODATA_code pixel with empty DataDrawer; continue to next MapPixel_ID
		if (Folder_count == 0) { continue; }

		//Flag_Put_FolderOutsideMap is true if ReferenceStationOutsideMap is 1 and MapPixel >= nRows * nCols; reference station appended to end of map
		bool Flag_Put_FolderOutsideMap = (input->SimulationStringParams["ReferenceStationOutsideMap"] == "1" && MapPixel_ID >= Inputs::nRows * Inputs::nCols);

		//Flag_Use_ReferenceStationFolder is true if Flag_InputXml_ReferenceStationFolder && isReferenceStationPixel(MapPixel_ID)
		//Note: Flag_InputXml_ReferenceStationFolder indicates HydroPlusConfig.xml contains DataFolder distinct for reference station
		bool Flag_Use_ReferenceStationFolder = (input->Flag_InputXml_ReferenceStationFolder && input->isReferenceStationPixel(MapPixel_ID));
		//InputXml defined with ternary using Flag_InputXml_ReferenceStationFolder, InputXml_ReferenceStationFolder if true, else InputXml_StandardFolder
		//Note: InputXml replaces InputXml_StandardFolder and InputXml_ReferenceStationFolder 
		input->InputXml = Flag_Use_ReferenceStationFolder
			? input->InputXml_ReferenceStationFolder
			: input->InputXml_StandardFolder;
		//InputXml_string defined with ternary, InputXmlString_ReferenceStationFolder if true, else InputXmlString_StandardFolder
		//Note: InputXml_string replaces InputXmlString_StandardFolder and InputXmlString_ReferenceStationFolder 
		input->InputXml_string = Flag_Use_ReferenceStationFolder
			? input->InputXmlString_ReferenceStationFolder
			: input->InputXmlString_StandardFolder;

		//If Type not equal to BulkArea then abort
		//Note: Consider refactor to allow for other folder Type, such as ReferenceFolder or GI
		if (input->InputXml_string["Type"] != "BulkArea") {
			//If HydroPlusConfig Type is not BulkArea , then abort program
			cout << "Warning: HydroPlusConfig.xml Type = " << input->InputXml_string["Type"] << " is incompatible with Model = SpatialTemperatureHydro." << endl;
			cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
			cout << "Explanation: The model SpatialTemperatureHydro expects Type = BulkArea to complete water and energy balances." << endl;
			cout << "Correction: In the HydroPlusConfig.xml file, set the DataFolder element Type to BulkArea." << endl;
			//Call abort function, which ends the HydroPlus.exe simulation
			abort();
		}

		//Check_HydroPlusConfig_Inputs function performs quality assurance on HydroPlusConfig.xml inputs for each folder
		Check_HydroPlusConfig_Inputs(input, beC, Directory_Input_CLArg, MapPixel_ID, DataFolder_ID);

		//Call Folder_CoverData_Spatial function to get BulkArea parameters, sending pointers to folder, input, and MapPixel_ID
		Folder_CoverData_Spatial(input, beC, MapPixel_ID, DataFolder_ID, Folder_Type_ID);

		//If not (ReferenceStationOutsideMap is 1 and isReferenceStationPixel is true) then enter
		//Note: Only enter for MapPixel_ID that are inside map when computing catchment areas
		if (!(input->SimulationStringParams["ReferenceStationOutsideMap"] == "1" && input->isReferenceStationPixel(MapPixel_ID))) {
			//Catchment_Type_Area_m2 (m2) contains entire catchment area of this folder type
			input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID] += beC->by_key(MapPixel_ID, DataFolder_ID, "Area_m2");
			//Call Catchment_CoverData_FolderType function to compute weighted areas across catchment
			Catchment_CoverData_FolderType(input, beC, MapPixel_ID, DataFolder_ID, Folder_Type_ID);
		}
	}

	//Catchment_CoverData_FolderType_Summarize_Spatial function will summarize catchment data once MapPixel_ID loop has finished
	//Note: Algorithm at end of loop ensures catchment_ImperviousCover_noTreeCanopy_frac and other catchment covers sum to 1.0
	Catchment_CoverData_FolderType_Summarize_Spatial(input, Folder_Type_ID);	
}	

//BuildDataOrganizer_Statistical function called for Model = StatisticalHydro
void BuildDataOrganizer::BuildDataOrganizer_Statistical(DataOrganizer* organizer, Inputs* input, CompactRagged* beC, string Directory_Input_CLArg)
{
	//DataFolder_counter is initialized to zero
	int DataFolder_counter = 0;
	//input->RepoDict["Catchment_PerviousArea_AffectingStorageDeficit_m2"] reset to zero
	input->RepoDict["Catchment_PerviousArea_AffectingStorageDeficit_m2"] = 0;

	//Loop through the DataDrawers, where the upper bound is based on the general DataDrawer attribute .size()
	//Note: DataDrawers.size() defined in HydroPlusConfig.xml as number of DataDrawer elements within the DataOrganizer
	for (int DataDrawer_ID = 0; DataDrawer_ID < input->DataDrawers.size(); ++DataDrawer_ID) {
		
		//Initialize GI index for mapping contributing areas
		size_t GI_Index = 0;

		//Loop through the DataFolders in each DataDrawer[DataDrawer_ID], upper bound indicated by .size()
		//Note: DataDrawers[DataDrawer_ID].size() defined in HydroPlusConfig.xml as number of DataFolder elements within the DataDrawer
		//Note: DataDrawers[0] contains the first DataFolder in vector, which is the BulkArea in HydroPlusConfig.xml file
		for (int DataFolder_ID = 0; DataFolder_ID < input->DataDrawers[DataDrawer_ID].size(); ++DataFolder_ID) {
			//Folder_Type_ID set and reset to -1; it will track Folder as BulkArea (0) of GreenInfrastructure (1)
			int Folder_Type_ID = -1;

			//If 1st DataDrawer and 1st DataFolder then 
			if (DataDrawer_ID == 0 && DataFolder_ID == 0) {
				//Catchment_Type_Area_m2 initialized to clear
				input->RepoVecDict["Catchment_Type_Area_m2"].clear();
			}

			//If Type is BulkArea then Folder_Type_ID is 0
			if (beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "BulkArea") {
				Folder_Type_ID = 0;
			}
			//If Type is a GI (not BulkArea) then Folder_Type_ID is 1
			else if (beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "BioRetention" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RainGarden" ||
				beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "InfilTrench" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "Swale" ||
				beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "PermeablePavement" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "GreenRoof" ||
				beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RoofDisconnect" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RainBarrel") {
				Folder_Type_ID = 1;
			}

			//If Folder_Type_ID >= 0 then it is BulkArea or GI, and enter for variable updates
			if (Folder_Type_ID >= 0) {
				//FolderType_index is searched as Folder_Type_ID with find(input->FolderType_List.begin(), input->FolderType_List.end(), Folder_Type_ID
				auto FolderType_index = find(input->FolderType_List.begin(), input->FolderType_List.end(), Folder_Type_ID);
				//dynamic_index is defined
				size_t dynamic_index;
				//If FolderType_index is not found in FolderType_List.end() then new Folder_Type_ID found, append to vectors
				if (FolderType_index == input->FolderType_List.end()) {
					//FolderType_List.push_back(Folder_Type_ID) 
					input->FolderType_List.push_back(Folder_Type_ID);
					//RepoVecDict["Catchment_Type_Area_m2"].push_back(0.0); initilize vector
					input->RepoVecDict["Catchment_Type_Area_m2"].push_back(0.0);
					//dynamic_index = input->FolderType_List.size() - 1; define dynamic_index for 0-based indexing
					dynamic_index = input->FolderType_List.size() - 1;
				}
				//Else FolderType_index was found in FolderType_List
				else {
					//dynamic_index = distance(input->FolderType_List.begin(), FolderType_index); finds index in FolderType_List
					dynamic_index = distance(input->FolderType_List.begin(), FolderType_index);
				}

				//If Folder_Type_ID is 0 (BulkArea) and Model_Selection is SpatialBufferwGI
				if (Folder_Type_ID == 0 && input->SimulationStringParams["Model_Selection"] == "SpatialBufferwGI") {
					//compute gi area and it;s contributing area, save to a vector
					double GI_Area_m2 = input->BufferGIAreaCalc(GI_Index);
					double GI_Contributing_Area_m2 = input->BufferGIContributingAreaCalc(GI_Index);
					input->GI_Area_m2.push_back(GI_Area_m2);
					input->GI_Contributing_Area_m2.push_back(GI_Contributing_Area_m2);
					//Area_m2 updated by GI_Contributing_Area_m2 - GI_Area_m2, the area of BulkArea drainage without GI
					beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_m2") = GI_Contributing_Area_m2 - GI_Area_m2;
				}
				//If Folder_Type_ID is 1 (GI) and Model_Selection is SpatialBufferwGI
				else if (Folder_Type_ID == 1 && input->SimulationStringParams["Model_Selection"] == "SpatialBufferwGI") {
					//Area_m2 updated by BufferGIAreaCalc(GI_Index), the area of GI folder
					beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_m2") = input->BufferGIAreaCalc(GI_Index);
					//GI_Index incremented to the next GI contributing area
					GI_Index = GI_Index + 1;
					//GI_list has appended adding GI type to GI_list (for SpatialBuffer)
					input->GI_list.push_back(beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type"));
				}

				//RepoVecDict["Catchment_Type_Area_m2"][dynamic_index] += beC->by_key(MapPixel_ID, DataFolder_ID, "Area_m2"); update Catchment area
				input->RepoVecDict["Catchment_Type_Area_m2"][dynamic_index] += beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_m2");
			}
			//StorageDeficit_VadoseZone_m (m) set as single reference value for entire catchment
			input->RepoDict["StorageDeficit_VadoseZone_m"] = input->AveSMD;

			//Check_HydroPlusConfig_Inputs function performs quality assurance on HydroPlusConfig.xml inputs for each folder
			Check_HydroPlusConfig_Inputs(input, beC, Directory_Input_CLArg, DataDrawer_ID, DataFolder_ID);

			//Folder_CoverData_Statistical function determines land cover calculations for folder
			Folder_CoverData_Statistical(input, beC, DataDrawer_ID, DataFolder_ID);

			//Call Catchment_CoverData_FolderType function to compute weighted areas across catchment
			Catchment_CoverData_FolderType(input, beC, DataDrawer_ID, DataFolder_ID, Folder_Type_ID);

			//DataFolder_counter is advanced to loop through all DataDrawers and DataFolders
			DataFolder_counter = DataFolder_counter + 1;
		}
	}
}

//Folder_CoverData_Spatial function called for Model = SpatialTemperatureHydro
void BuildDataOrganizer::Folder_CoverData_Spatial(Inputs* input, CompactRagged* beC, int MapPixel_ID, int DataFolder_ID, int Folder_Type_ID)
{
	//TreeCanopyCover_overImpervious_frac (fraction) is derived from treecover.asc and imperviouscover.asc, only occurs if TC+IC > 1 
	beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") = input->TreeCoverOnImperviousCover_frac[MapPixel_ID];
	//TreeCanopyCover_overPervious_frac (fraction) is derived from treecover.asc and imperviouscover.asc, defaults to all TC 
	beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") = input->TreeCoverOnPerviousCover_frac[MapPixel_ID];

	//ShortVegCover_noTreeCanopy_frac (fraction) is derived when TC+IC < 1, and is function of NLCD value; see Inputs::LandCoverAssignment_by_NLCD_Class
	beC->by_key(MapPixel_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") = input->ShortVegCoverNoTC_frac[MapPixel_ID];
	//SoilCover_noTreeCanopy_frac (fraction) is derived when TC+IC < 1, and is function of NLCD value; see Inputs::LandCoverAssignment_by_NLCD_Class
	beC->by_key(MapPixel_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") = input->SoilCoverNoTC_frac[MapPixel_ID];
	//PermeablePavementCover_noTreeCanopy_frac (fraction) is derived from HydroPlusConfig.xml and is not function of NLCD value
	//Note: Consider refactor to allow this option within the Inputs::LandCoverAssignment_by_NLCD_Class function or set to zero 
	beC->by_key(MapPixel_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac") = input->PermeablePavementCover_frac[MapPixel_ID];
	//WaterCover_noTreeCanopy_frac (fraction) is derived when TC+IC < 1, and is function of NLCD value; see Inputs::LandCoverAssignment_by_NLCD_Class
	beC->by_key(MapPixel_ID, DataFolder_ID, "WaterCover_noTreeCanopy_frac") = input->WaterCoverNoTC_frac[MapPixel_ID];

	//ImperviousCover_noTreeCanopy_frac (fraction) is derived from treecover.asc and imperviouscover.asc, defaults to all IC 
	beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac") = input->ImperviousCoverNoTreeCover_frac[MapPixel_ID];

	//ImperviousCover_frac (fraction) combines TreeCanopyCover_overImpervious_frac and ImperviousCover_noTreeCanopy_frac
	beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_frac") = beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac");

	//PerviousCover_frac (fraction) combines TreeCanopyCover_overPervious_frac, ShortVegCover_noTreeCanopy_frac, SoilCover_noTreeCanopy_frac, PermeablePavementCover_noTreeCanopy_frac
	beC->by_key(MapPixel_ID, DataFolder_ID, "PerviousCover_frac") = beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac");

	//TreeCover_frac (fraction) combines TreeCanopyCover_overImpervious_frac, TreeCanopyCover_overPervious_frac
	beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCover_frac") = beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac");

	//Section to scale soil terms based on vegetation cover based on this literature:
	//Aubertin, G. M. (1971). Nature and extent of macropores in forest soils and their influence on subsurface water movement (Vol. 192): Northeastern Forest Experiment Station. 
	//Endreny, T. A., Kwon, P., Williamson, T. N., & Evans, R. (2019). Reduced Soil Macropores and Forest Cover Reduce Warm-Season Baseflow below Ecological Thresholds in the Upper Delaware River Basin. Journal of the American Water Resources Association, 55(5), 1268-1287. doi:10.1111/1752-1688.12777
	//Harman, C. J., Lohse, K. A., Troch, P. A., & Sivapalan, M. (2014). Spatial patterns of vegetation, soils, and microtopography from terrestrial laser scanning on two semiarid hillslopes of contrasting lithology. Journal of Geophysical Research: Biogeosciences, 119(2), 163-180. doi:https://doi.org/10.1002/2013JG002507
	//Holdo, R. M., Nippert, J. B., & Mack, M. C. (2018). Rooting depth varies differentially in trees and grasses as a function of mean annual rainfall in an African savanna. Oecologia, 186(1), 269-280. doi:10.1007/s00442-017-4011-4
	//Pitt, R., Chen, S. E., Clark, S., Lantrip, J., Ong, C. K., & Voorhees, J. (2003). Infiltration Through Compacted Urban Soils and Effects on Biofiltration Design. In W. James (Ed.), Practical Modeling of Urban Water Systems (Vol. 11, pp. 217-252). Guelph, Ontario: CHI.
	//Rossman, L. A. (2015). Storm Water Management Model User's Manual Version 5.1. US Environmental Protection Agency. Cincinnati, HO. EPA/600/R-14/413b: 352. 
	//ASCE/WEF. (1992). Design and Construction of Urban Stormwater Management Systems. New York: American Society of Civil Engineers and the Water Environment Federation.

	//Soil_Macropore_frac from HydroPlusConfig.xml is scaled values based on land cover as in Endreny et al. (2019), Aubertin (1971), Pitt et al. (2003)
	//Note: Soil_Macropore_frac value decreases from trees to short vegetation to soil, increases with age; not simulated below impervious area
	//Note: Refactor option to define Soil_Macropore_PermeablePavementCover_frac for PermeablePavementCover_noTreeCanopy_frac
	beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_Macropore_frac") =
		input->SafeDivide((beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_Macropore_TreeCover_frac") * beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") +
			beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_Macropore_SVegCover_frac") * beC->by_key(MapPixel_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") +
			beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_Macropore_SoilCover_frac") * beC->by_key(MapPixel_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") +
			beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_Macropore_SoilCover_frac") * beC->by_key(MapPixel_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")),
		(beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") +
			beC->by_key(MapPixel_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")));

	//Evapotranspiration_Depth_m from HydroPlusConfig.xml is scaled values based on land cover as in Holdo et al. (2018) and other studies
	//Note: Evapotranspiration_Depth_m value decreases from trees to short vegetation to soil, increases with age; simulated below impervious area
	//Note: Refactor Option: Create EvapotranspirationDepth_PermeablePavementCover_m for PermeablePavementCover_noTreeCanopy_frac 
	beC->by_key(MapPixel_ID, DataFolder_ID, "Evapotranspiration_Depth_m") =
		input->SafeDivide((beC->by_key(MapPixel_ID, DataFolder_ID, "EvapotranspirationDepth_TreeCover_m") * beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCover_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "EvapotranspirationDepth_SVegCover_m") * beC->by_key(MapPixel_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "EvapotranspirationDepth_SoilCover_m") * beC->by_key(MapPixel_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "EvapotranspirationDepth_SoilCover_m") * beC->by_key(MapPixel_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")), (beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCover_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")));
	//Evapotranspiration_Depth_max_m = max(EvapotranspirationDepth_TreeCover_m, EvapotranspirationDepth_SVegCover_m)
	input->InputXml["Evapotranspiration_Depth_max_m"] = max(beC->by_key(MapPixel_ID, DataFolder_ID, "EvapotranspirationDepth_TreeCover_m"), beC->by_key(MapPixel_ID, DataFolder_ID, "EvapotranspirationDepth_SVegCover_m"));
	//Evapotranspiration_Depth_max_m = max(Evapotranspiration_Depth_max_m, EvapotranspirationDepth_SoilCover_m)
	input->InputXml["Evapotranspiration_Depth_max_m"] = max(input->InputXml["Evapotranspiration_Depth_max_m"], beC->by_key(MapPixel_ID, DataFolder_ID, "EvapotranspirationDepth_SoilCover_m"));

	//PerviousDepressionStorage_mm from HydroPlusConfig.xml is scaled values based on land cover as in ASCE/WEF (1992), Rossman (2015) Table A5, Harman et al. (2014)
	//Note: PerviousDepressionStorage_mm value decreases from trees to short vegetation to soil, increases with age
	//Note: Refactor Option: Create PermeablePavementStorage_noTreeCover_mm for PermeablePavementCover_noTreeCanopy_frac
	beC->by_key(MapPixel_ID, DataFolder_ID, "PerviousDepressionStorage_mm") =
		input->SafeDivide((beC->by_key(MapPixel_ID, DataFolder_ID, "PerviousDepressionStorage_TreeCover_mm") * beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "PerviousDepressionStorage_SVegCover_mm") * beC->by_key(MapPixel_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "PerviousDepressionStorage_SoilCover_mm") * beC->by_key(MapPixel_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousDepressionStorage_noTreeCover_mm") * beC->by_key(MapPixel_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")), (beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")));

	//ImperviousDepressionStorage_mm from HydroPlusConfig.xml is scaled values based on land cover as in ASCE/WEF (1992), Rossman (2015) Table A5, Harman et al. (2014)
	//Note: ImperviousDepressionStorage_mm value increases with trees, due to leaf and organic litter, root generated undulations, increases w age
	beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousDepressionStorage_mm") =
		input->SafeDivide((beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousDepressionStorage_noTreeCover_mm") * beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousDepressionStorage_TreeCover_mm") * beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac")), (beC->by_key(MapPixel_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") + beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac")));

	//Storage_ImperviousPondedWater_Max_m (m) is ImperviousDepressionStorage_mm * Ratio_m_to_mm
	beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_ImperviousPondedWater_Max_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousDepressionStorage_mm") * Ratio_m_to_mm;

	double DCIA_frac = 0;
	//If for BulkArea the PerviousCover_frac = 0, all impervious area drains to outlet and DCIA_frac must equal 1, despite HydroPlusConfig.xml inputs
	//If for GI Types, there are cases such as Roof Disconnect when PerviousCover_frac = 0 and DCIA should remain < 1
	if (beC->by_key(MapPixel_ID, DataFolder_ID, "PerviousCover_frac") <= 0 && beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "BulkArea") {
		//DCIA_frac = 1 forces all impervious area to drain to outlet given no pervious area
		DCIA_frac = 1;
	}
	else {
		//DCIA_frac = HydroPlusConfig.xml input, and allows either for some impervious area to drain to pervious area or GI
		DCIA_frac = input->ConnectedImpervious[MapPixel_ID];
	}

	//ImperviousCover_DrainsToOutlet_frac (fraction) is product of DCIA_frac and ImperviousCover_frac, including water and IC under TC
	beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_DrainsToOutlet_frac") = DCIA_frac * beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_frac");
	//ImperviousCover_DrainsToPervious_frac (fraction) is product of (1-DCIA_frac) and ImperviousCover_frac, including water and IC under TC
	beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_DrainsToPervious_frac") = (1.0 - DCIA_frac) * beC->by_key(MapPixel_ID, DataFolder_ID, "ImperviousCover_frac");

	//Porosity_Drainable_m3pm3 (m3/m3) is gravitational water for the catchment, used to compute catchment average Depth_to_Groundwater_Table_m (m); constant for catchment 
	input->InputXml["Porosity_Drainable_m3pm3"] = input->InputXml["Soil_SaturationPoint_m3pm3"] - input->InputXml["Soil_FieldCapacity_m3pm3"];
	//StorageDeficit_FieldCapacity_SoilEvapZone_Max_m (m) is water available for evapotranspiration, not available for gravitational drainage
	//Note: This can vary between folders across catchment with variation in folder Evapotranspiration_Depth_m
	//Note: Consider refactor to maintain version specific to soil, which has lower limit below Soil_WiltingPoint_m3pm3 used by plants
	beC->by_key(MapPixel_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_Max_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "Evapotranspiration_Depth_m") * (beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_FieldCapacity_m3pm3") - beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_WiltingPoint_m3pm3"));

	//Porosity_ThetaFc_ThetaWp_m3pm3 (m3/m3) is capillary water for the catchment, used to compute vadose zone capillary available water; constant for catchment 
	input->InputXml["Porosity_ThetaFc_ThetaWp_m3pm3"] = input->InputXml["Soil_FieldCapacity_m3pm3"] - input->InputXml["Soil_WiltingPoint_m3pm3"];

	//If Soil_MoistureInitial_m3pm3 > Soil_FieldCapacity_m3pm3 then
	if (beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_MoistureInitial_m3pm3") > beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_FieldCapacity_m3pm3")) {
		//StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m (m) equals zero, soil moisture is beyond Soil_FieldCapacity_m3pm3 and ...
		//Note: ... no capacity remains for tension held water
		//Note: StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m is constant across all TI bins ...
		//Note: ... regardless of TI bin variation in depth to groundwater, e.g., StorageDeficit_VadoseZone_TI_m / Porosity_Drainable_m3pm3
		beC->by_key(MapPixel_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m") = 0.0;
	}
	//Else Soil_MoistureInitial_m3pm3 (m3/m3) is less than Soil_FieldCapacity_m3pm3 then
	else {
		//StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m (m) equals Soil_FieldCapacity_m3pm3 - Soil_MoistureInitial_m3pm3 to compute ...
		//Note: ... tension held water available for evapotranspiration
		//Note: StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m is constant across all TI bins ...
		//Note: ... regardless of TI bin variation in depth to groundwater, e.g., StorageDeficit_VadoseZone_TI_m / Porosity_Drainable_m3pm3
		beC->by_key(MapPixel_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m") = beC->by_key(MapPixel_ID, DataFolder_ID, "Evapotranspiration_Depth_m") * (beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_FieldCapacity_m3pm3") - beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_MoistureInitial_m3pm3"));
	}
	//Storage_SoilEvapZone_TS_0th_m (m) computed using HydroPlusConfig.xml inputs to obtain exact initial condition, not end of time step condition
	beC->by_key(MapPixel_ID, DataFolder_ID, "Storage_SoilEvapZone_TS_0th_m") = (beC->by_key(MapPixel_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_Max_m") - beC->by_key(MapPixel_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m"));

	//Catchment variables updated
	//If (Type is BulkArea) or (Type not BulkArea and Flag_Exfiltration_to_Catchment is 1), then sum area draining to vadose zone shared by catchment
	//Note: Consider refactor for GI to add Vault storage area rather than Pervious cover area, given vault area can be larger than pervious area
	if ((beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "BulkArea") || (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "BulkArea" && beC->by_key(MapPixel_ID, DataFolder_ID, "Flag_Exfiltration_to_Catchment")== 1)) {
		//Catchment_PerviousArea_AffectingStorageDeficit_m2 (m2) contains entire catchment pervious area draining to vadose zone
		//Note: Catchment_PerviousArea_AffectingStorageDeficit_m2 influences the catchment variable, StorageDeficit_VadoseZone_m
		input->RepoDict["Catchment_PerviousArea_AffectingStorageDeficit_m2"] += beC->by_key(MapPixel_ID, DataFolder_ID, "Area_m2") * beC->by_key(MapPixel_ID, DataFolder_ID, "PerviousCover_frac");
	}

	//Catchment_LeafAreaIndex_Tree_m2m2 set to input->InputXml["LeafAreaIndex_Tree_m2pm2"]
	input->RepoDict["Catchment_LeafAreaIndex_Tree_m2m2"] = input->InputXml["LeafAreaIndex_Tree_m2pm2"];
	input->RepoDict["Catchment_LeafAreaIndex_SVeg_m2m2"] = input->InputXml["LeafAreaIndex_SVeg_m2pm2"];
}

//Catchment_CoverData_FolderType_Summarize_Spatial funciton summarizes land cover data into catchment totals for Model = SpatialTemperatureHydro
void BuildDataOrganizer::Catchment_CoverData_FolderType_Summarize_Spatial(Inputs* input, int Folder_Type_ID)
{
	//Folder_Type_ID defined as 0 for BulkArea
	Folder_Type_ID = 0;
	//If input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID] > 0 then enter for division
	//Note: WaterBalance_Summary::writeWaterBalanceFile uses same calculations, so consider refactor to consolidate
	if (input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID] > 0) {
		//catchment_TotalPerviousCover_frac (frac) = Inputs::roundToDecimalPlaces(TotalPerviousCover_Type_m2 / Catchment_Type_Area_m2, 3)
		//Note: RHS function divides by 1000 after taking integer of the term that takes product with 1000 to round up
		input->RepoDict["Catchment_TotalPerviousCover_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["TotalPerviousCover_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID],3);
		input->RepoDict["Catchment_TotalImperviousCover_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["TotalImperviousCover_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_TotalTreeCover_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["TotalTreeCover_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["TreeCanopyCover_overImpervious_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["TreeCanopyCover_overPervious_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["ImperviousCover_noTreeCanopy_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["ShortVegCover_noTreeCanopy_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["SoilCover_noTreeCanopy_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["PermeablePavementCover_noTreeCanopy_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["WaterCover_noTreeCanopy_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_InfiltExcessGovernedArea_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["InfiltExcessGovernedArea_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_DCIA_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["DCIA_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_MacroPore_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["MacroPore_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
		input->RepoDict["Catchment_MacroPore_frac"] = Inputs::roundToDecimalPlaces(input->RepoVecDict["MacroPore_Type_m2"][Folder_Type_ID] / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID], 3);
	}
	//catchment_TotalPerviousCover_frac (frac) = catchment_TreeCanopyCover_overPervious_frac + catchment_ShortVegCover_noTreeCanopy_frac + catchment_SoilCover_noTreeCanopy_frac + catchment_PermeablePavementCover_noTreeCanopy_frac
	input->RepoDict["Catchment_TotalPerviousCover_frac"] = input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] + input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"];

	//catchment_TotalImperviousCover_frac (frac) = catchment_ImperviousCover_noTreeCanopy_frac + catchment_TreeCanopyCover_overImpervious_frac
	input->RepoDict["Catchment_TotalImperviousCover_frac"] = input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"];

	//catchment_TotalTreeCover_frac (frac) = catchment_TreeCanopyCover_overPervious_frac + catchment_TreeCanopyCover_overImpervious_frac
	input->RepoDict["Catchment_TotalTreeCover_frac"] = input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] + input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"];

	//TotalCover_frac (frac) initialized to equal sum of catchment_ImperviousCover_noTreeCanopy_frac (frac), catchment_TreeCanopyCover_overImpervious_frac (frac), catchment_TreeCanopyCover_overPervious_frac (frac), catchment_ShortVegCover_noTreeCanopy_frac (frac), catchment_SoilCover_noTreeCanopy_frac (frac), catchment_PermeablePavementCover_noTreeCanopy_frac (frac), catchment_WaterCover_noTreeCanopy_frac (frac)
	double TotalCover_frac = input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"] + input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] + input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"];

	//TotalCover_Remainder_frac (frac) initialized to equal 1.0 - TotalCover_frac
	double TotalCover_Remainder_frac = 1.0 - TotalCover_frac;

	//If TotalCover_Remainder_frac != 0.0 then add the remaining gap in a sequence that lastly updates tree cover, presumed correct
	//Note: Algorithm could be improved to search for smallest unit of area (frac) before setting anything to zero but ...
	//Note: ... Algorithm will never likely set anything to zero due to (1.0 - TotalCover_frac) naturally positive, without need for abs
	if (TotalCover_Remainder_frac != 0.0) {
		if (input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"] > 0.0) {
			//TotalCover_Remainder_wo_frac (frac) initialized to equal 1.0 - (TotalCover_frac - catchment_PermeablePavementCover_noTreeCanopy_frac)
			double TotalCover_Remainder_wo_frac = 1.0 - (TotalCover_frac - input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"]);
			//catchment_PermeablePavementCover_noTreeCanopy_frac (frac) = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac)
			input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3);
			//Clamp to ensure variable is between 0 and 1 
			input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"] = clamp(input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"], 0.0, 1.0);
		}
		else if (input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] > 0.0) {
			//TotalCover_Remainder_wo_frac (frac) initialized to equal 1.0 - (TotalCover_frac - catchment_SoilCover_noTreeCanopy_frac)
			double TotalCover_Remainder_wo_frac = 1.0 - (TotalCover_frac - input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"]);
			//catchment_SoilCover_noTreeCanopy_frac (frac) = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac)
			input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3);
			//Clamp to ensure variable is between 0 and 1 
			input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] = clamp(input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"], 0.0, 1.0);
		}
		else if (input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"] > 0.0) {
			//TotalCover_Remainder_wo_frac (frac) initialized to equal 1.0 - (TotalCover_frac - catchment_WaterCover_noTreeCanopy_frac)
			double TotalCover_Remainder_wo_frac = 1.0 - (TotalCover_frac - input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"]);
			//catchment_WaterCover_noTreeCanopy_frac (frac) = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac)
			input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3);
			//Clamp to ensure variable is between 0 and 1 
			input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"] = clamp(input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"], 0.0, 1.0);
		}
		else if (input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] > 0.0) {
			//TotalCover_Remainder_wo_frac (frac) initialized to equal 1.0 - (TotalCover_frac - catchment_ShortVegCover_noTreeCanopy_frac)
			double TotalCover_Remainder_wo_frac = 1.0 - (TotalCover_frac - input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"]);
			//catchment_ShortVegCover_noTreeCanopy_frac (frac) = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3)
			input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3);
			//Clamp to ensure variable is between 0 and 1 
			input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] = clamp(input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"], 0.0, 1.0);
		}
		else if (input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] > 0.0) {
			//TotalCover_Remainder_wo_frac (frac) initialized to equal 1.0 - (TotalCover_frac - catchment_ImperviousCover_noTreeCanopy_frac)
			double TotalCover_Remainder_wo_frac = 1.0 - (TotalCover_frac - input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"]);
			//catchment_ImperviousCover_noTreeCanopy_frac (frac) = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3)
			input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3);
			//Clamp to ensure variable is between 0 and 1 
			input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] = clamp(input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"], 0.0, 1.0);
		}
		else if (input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"] > 0.0) {
			//TotalCover_Remainder_wo_frac (frac) initialized to equal 1.0 - (TotalCover_frac - catchment_TreeCanopyCover_overImpervious_frac)
			double TotalCover_Remainder_wo_frac = 1.0 - (TotalCover_frac - input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"]);
			//catchment_TreeCanopyCover_overImpervious_frac (frac) = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3)
			input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"] = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3);
			//Clamp to ensure variable is between 0 and 1 
			input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"] = clamp(input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"], 0.0, 1.0);
		}
		else if (input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] > 0.0) {
			//TotalCover_Remainder_wo_frac (frac) initialized to equal 1.0 - (TotalCover_frac - catchment_TreeCanopyCover_overPervious_frac)
			double TotalCover_Remainder_wo_frac = 1.0 - (TotalCover_frac - input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"]);
			//catchment_TreeCanopyCover_overPervious_frac (frac) = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3)
			input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] = Inputs::roundToDecimalPlaces(TotalCover_Remainder_wo_frac, 3);
			//Clamp to ensure variable is between 0 and 1 
			input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] = clamp(input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"], 0.0, 1.0);
		}
		//catchment_TotalPerviousCover_frac (frac) = catchment_TreeCanopyCover_overPervious_frac + catchment_ShortVegCover_noTreeCanopy_frac + catchment_SoilCover_noTreeCanopy_frac + catchment_PermeablePavementCover_noTreeCanopy_frac
		input->RepoDict["Catchment_TotalPerviousCover_frac"] = input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] + input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"];

		//catchment_TotalImperviousCover_frac (frac) = catchment_ImperviousCover_noTreeCanopy_frac + catchment_TreeCanopyCover_overImpervious_frac
		input->RepoDict["Catchment_TotalImperviousCover_frac"] = input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] + input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"];

		//catchment_TotalTreeCover_frac (frac) = catchment_TreeCanopyCover_overPervious_frac + catchment_TreeCanopyCover_overImpervious_frac
		input->RepoDict["Catchment_TotalTreeCover_frac"] = input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] + input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"];
	}

}

//Folder_CoverData_Statistical function called for Model = StatisticalHydro
void BuildDataOrganizer::Folder_CoverData_Statistical(Inputs* input, CompactRagged* beC, int DataDrawer_ID, int DataFolder_ID)
{
	//If HydroPlusConfig.xml has DataFolder Type for GI then define RepoDict variables related to water transfer between GI and BulkArea
	if (beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "BioRetention" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RainGarden" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "InfilTrench" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "Swale" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "PermeablePavement" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "GreenRoof" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RoofDisconnect" || beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "RainBarrel") {

		//Flag_GI_Simulated flag set = 1, ensuring transfer of water between GI and BulkArea
		input->RepoDict["Flag_GI_Simulated"] = 1;
		//PerAreaTreated_frac (fraction) is fraction of BulkArea pervious cover that drains to GI
		input->RepoDict["BulkAreaPervious_DrainingToGI_frac"] = beC->by_key(DataDrawer_ID, DataFolder_ID, "PerAreaTreated_frac");
		//ImpAreaTreated_frac (fraction) is fraction of BulkArea impervious cover that drains to GI
		input->RepoDict["BulkAreaImpervious_DrainingToGI_frac"] = beC->by_key(DataDrawer_ID, DataFolder_ID, "ImpAreaTreated_frac");
		//BulkAreaWater_DrainingToGI_frac (fraction) is fraction of BulkArea water cover that drains to GI
		input->RepoDict["BulkAreaWater_DrainingToGI_frac"] = beC->by_key(DataDrawer_ID, DataFolder_ID, "WaterAreaTreated_frac");
	}
	else {
		//Flag_GI_Simulated flag set = 0, ensuring no transfer of water between GI and BulkArea
		input->RepoDict["Flag_GI_Simulated"] = 0;
	}

	//ImperviousCover_frac (fraction) combines TreeCanopyCover_overImpervious_frac and ImperviousCover_noTreeCanopy_frac
	beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_frac") = beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac");

	//PerviousCover_frac (fraction) combines TreeCanopyCover_overPervious_frac, ShortVegCover_noTreeCanopy_frac, SoilCover_noTreeCanopy_frac
	beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousCover_frac") = beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac");

	//TreeCover_frac (fraction) combines TreeCanopyCover_overImpervious_frac, TreeCanopyCover_overPervious_frac
	beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCover_frac") = beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac");

	//Section to scale soil terms based on vegetation cover based on this literature:
	//Aubertin, G. M. (1971). Nature and extent of macropores in forest soils and their influence on subsurface water movement (Vol. 192): Northeastern Forest Experiment Station. 
	//Endreny, T. A., Kwon, P., Williamson, T. N., & Evans, R. (2019). Reduced Soil Macropores and Forest Cover Reduce Warm-Season Baseflow below Ecological Thresholds in the Upper Delaware River Basin. Journal of the American Water Resources Association, 55(5), 1268-1287. doi:10.1111/1752-1688.12777
	//Harman, C. J., Lohse, K. A., Troch, P. A., & Sivapalan, M. (2014). Spatial patterns of vegetation, soils, and microtopography from terrestrial laser scanning on two semiarid hillslopes of contrasting lithology. Journal of Geophysical Research: Biogeosciences, 119(2), 163-180. doi:https://doi.org/10.1002/2013JG002507
	//Holdo, R. M., Nippert, J. B., & Mack, M. C. (2018). Rooting depth varies differentially in trees and grasses as a function of mean annual rainfall in an African savanna. Oecologia, 186(1), 269-280. doi:10.1007/s00442-017-4011-4
	//Pitt, R., Chen, S. E., Clark, S., Lantrip, J., Ong, C. K., & Voorhees, J. (2003). Infiltration Through Compacted Urban Soils and Effects on Biofiltration Design. In W. James (Ed.), Practical Modeling of Urban Water Systems (Vol. 11, pp. 217-252). Guelph, Ontario: CHI.
	//Rossman, L. A. (2015). Storm Water Management Model User's Manual Version 5.1. US Environmental Protection Agency. Cincinnati, HO. EPA/600/R-14/413b: 352. 
	//ASCE/WEF. (1992). Design and Construction of Urban Stormwater Management Systems. New York: American Society of Civil Engineers and the Water Environment Federation.

	//Soil_Macropore_frac from HydroPlusConfig.xml is scaled values based on land cover as in Endreny et al. (2019), Aubertin (1971), Pitt et al. (2003)
	//Note: Soil_Macropore_frac value decreases from trees to short vegetation to soil, increases with age; not simulated below impervious area
	//Note: Refactor option to define Soil_Macropore_PermeablePavementCover_frac for PermeablePavementCover_noTreeCanopy_frac
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Macropore_frac") =
		input->SafeDivide((beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Macropore_TreeCover_frac") * beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") +
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Macropore_SVegCover_frac") * beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") +
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Macropore_SoilCover_frac") * beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") +
			beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Macropore_SoilCover_frac") * beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")),
			(beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") +
				beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")));

	//Evapotranspiration_Depth_m from HydroPlusConfig.xml is scaled values based on land cover as in Holdo et al. (2018) and other studies
	//Note: Evapotranspiration_Depth_m value decreases from trees to short vegetation to soil, increases with age; simulated below impervious area
	//Note: Refactor Option: Create EvapotranspirationDepth_PermeablePavementCover_m for PermeablePavementCover_noTreeCanopy_frac 
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Evapotranspiration_Depth_m") =
		input->SafeDivide((beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapotranspirationDepth_TreeCover_m") * beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCover_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapotranspirationDepth_SVegCover_m") * beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapotranspirationDepth_SoilCover_m") * beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapotranspirationDepth_SoilCover_m") * beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")), (beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCover_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")));

	//Evapotranspiration_Depth_max_m = max(EvapotranspirationDepth_TreeCover_m, EvapotranspirationDepth_SVegCover_m)
	input->InputXml["Evapotranspiration_Depth_max_m"] = max(beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapotranspirationDepth_TreeCover_m"), beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapotranspirationDepth_SVegCover_m"));
	//Evapotranspiration_Depth_max_m = max(Evapotranspiration_Depth_max_m, EvapotranspirationDepth_SoilCover_m)
	input->InputXml["Evapotranspiration_Depth_max_m"] = max(input->InputXml["Evapotranspiration_Depth_max_m"], beC->by_key(DataDrawer_ID, DataFolder_ID, "EvapotranspirationDepth_SoilCover_m"));

	//PerviousDepressionStorage_mm from HydroPlusConfig.xml is scaled values based on land cover as in ASCE/WEF (1992), Rossman (2015) Table A5, Harman et al. (2014)
	//Note: PerviousDepressionStorage_mm value decreases from trees to short vegetation to soil, increases with age
	//Note: Refactor Option: Create PermeablePavementStorage_noTreeCover_mm for PermeablePavementCover_noTreeCanopy_frac
	beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousDepressionStorage_mm") =
		input->SafeDivide((beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousDepressionStorage_TreeCover_mm") * beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousDepressionStorage_SVegCover_mm") * beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousDepressionStorage_SoilCover_mm") * beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousDepressionStorage_noTreeCover_mm") * beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")), (beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac")));


	//ImperviousDepressionStorage_mm from HydroPlusConfig.xml is scaled values based on land cover as in ASCE/WEF (1992), Rossman (2015) Table A5, Harman et al. (2014)
	//Note: ImperviousDepressionStorage_mm value increases with trees, due to leaf and organic litter, root generated undulations, increases w age
	beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousDepressionStorage_mm") =
		input->SafeDivide((beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousDepressionStorage_noTreeCover_mm") * beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousDepressionStorage_TreeCover_mm") * beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac")), (beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac")));

	//Storage_ImperviousPondedWater_Max_m (m) is ImperviousDepressionStorage_mm * Ratio_m_to_mm
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_ImperviousPondedWater_Max_m") = beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousDepressionStorage_mm") * Ratio_m_to_mm;

	double DCIA_frac = 0;
	//If for BulkArea the PerviousCover_frac = 0, all impervious area drains to outlet and DCIA_frac must equal 1, despite HydroPlusConfig.xml inputs
	//If for GI Types, there are cases such as Roof Disconnect when PerviousCover_frac = 0 and DCIA should remain < 1
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousCover_frac") <= 0 && beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "BulkArea") {
		//DCIA_frac = 1 forces all impervious area to drain to outlet given no pervious area
		DCIA_frac = 1;
	}
	else {
		//DCIA_frac = HydroPlusConfig.xml input, and allows either for some impervious area to drain to pervious area or GI
		DCIA_frac = beC->by_key(DataDrawer_ID, DataFolder_ID, "DirectlyConnectedImperviousArea_frac");
	}

	//ImperviousCover_DrainsToOutlet_frac (fraction) is product of DCIA_frac and ImperviousCover_frac, including water and IC under TC
	beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_DrainsToOutlet_frac") = DCIA_frac * beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_frac");
	//ImperviousCover_DrainsToPervious_frac (fraction) is product of (1-DCIA_frac) and ImperviousCover_frac, including water and IC under TC
	beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_DrainsToPervious_frac") = (1.0 - DCIA_frac) * beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_frac");

	double lc_sum_frac = 0.0;
	double lc_gap_frac = 0.0;
	//lc_sum_frac is sum of ImperviousCover_frac, PerviousCover_frac, and WaterCover_noTreeCanopy_frac, which combine to account for all land cover
	//Note: This section will abort program if (ImperviousCover_frac + PerviousCover_frac + WaterCover_noTreeCanopy_frac) != 1
	lc_sum_frac = beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousCover_frac") + beC->by_key(DataDrawer_ID, DataFolder_ID, "WaterCover_noTreeCanopy_frac");
	//lc_gap_frac is absolute value of lc_sum_frac minus 1
	lc_gap_frac = abs(lc_sum_frac - 1.0);
	//If lc_gap_frac < Constant_1E_negative5 then lc_gap_frac equals zero
	if (lc_gap_frac < Constant_1E_negative5) {
		lc_gap_frac = 0.0;
	}
	
	//If lc_gap_frac > Constant_1E_negative5 then
	if (lc_gap_frac > Constant_1E_negative5) {
		//Explain why program aborted
		cout << endl << endl << "Program aborted due to " << beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") << " total land cover fraction != 1." << endl;
		//Determine gap in desired land cover fraction of 1.0
		lc_gap_frac = lc_sum_frac - 1;
		//Determine if the land cover has to be lowered or raised
		if (lc_gap_frac > 0) {
			cout << endl << "	Lower a " << beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") << " land cover value below by:	" << lc_gap_frac << endl << endl;
		}
		else {
			cout << endl << "	Raise a " << beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") << " land cover value below by:	" << abs(lc_gap_frac) << endl << endl;
		}
		//List all land cover types and their fractions
		cout << "	TreeCanopyCover_overPervious_frac:		" << beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") << endl;
		cout << "	TreeCanopyCover_overImpervious_frac:		" << beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") << endl;
		cout << "	ShortVegCover_noTreeCanopy_frac:		" << beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") << endl;
		cout << "	SoilCover_noTreeCanopy_frac:			" << beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") << endl;
		cout << "	PermeablePavementCover_noTreeCanopy_frac:	" << beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac") << endl;
		cout << "	ImperviousCover_noTreeCanopy_frac:		" << beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac") << endl;
		cout << "	WaterCover_noTreeCanopy_frac:			" << beC->by_key(DataDrawer_ID, DataFolder_ID, "WaterCover_noTreeCanopy_frac") << endl;

		//List total land cover fraction
		cout << "	Total Land cover fraction:			" << lc_sum_frac << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//Porosity_Drainable_m3pm3 (m3/m3) is gravitational water for the catchment, used to compute catchment average Depth_to_Groundwater_Table_m (m); constant for catchment 
	input->InputXml["Porosity_Drainable_m3pm3"] = input->InputXml["Soil_SaturationPoint_m3pm3"] - input->InputXml["Soil_FieldCapacity_m3pm3"];
	//StorageDeficit_FieldCapacity_SoilEvapZone_Max_m (m) is water available for evapotranspiration, not available for gravitational drainage
	//Note: This can vary between folders across catchment with variation in folder Evapotranspiration_Depth_m
	//Note: Consider refactor to maintain version specific to soil, which has lower limit below Soil_WiltingPoint_m3pm3 used by plants
	beC->by_key(DataDrawer_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_Max_m") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Evapotranspiration_Depth_m") * (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_FieldCapacity_m3pm3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_WiltingPoint_m3pm3"));

	//Porosity_ThetaFc_ThetaWp_m3pm3 (m3/m3) is capillary water for the catchment, used to compute vadose zone capillary available water; constant for catchment 
	input->InputXml["Porosity_ThetaFc_ThetaWp_m3pm3"] = input->InputXml["Soil_FieldCapacity_m3pm3"] - input->InputXml["Soil_WiltingPoint_m3pm3"];

	//If Soil_MoistureInitial_m3pm3 > Soil_FieldCapacity_m3pm3 then
	if (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_MoistureInitial_m3pm3") > beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_FieldCapacity_m3pm3")) {
		//StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m (m) equals zero, soil moisture is beyond Soil_FieldCapacity_m3pm3 and ...
		//Note: ... no capacity remains for tension held water
		//Note: StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m is constant across all TI bins ...
		//Note: ... regardless of TI bin variation in depth to groundwater, e.g., StorageDeficit_VadoseZone_TI_m / Porosity_Drainable_m3pm3
		beC->by_key(DataDrawer_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m") = 0.0;
	}
	//Else Soil_MoistureInitial_m3pm3 (m3/m3) is less than Soil_FieldCapacity_m3pm3 then
	else {
		//StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m (m) equals Soil_FieldCapacity_m3pm3 - Soil_MoistureInitial_m3pm3 to compute ...
		//Note: ... tension held water available for evapotranspiration
		//Note: StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m is constant across all TI bins ...
		//Note: ... regardless of TI bin variation in depth to groundwater, e.g., StorageDeficit_VadoseZone_TI_m / Porosity_Drainable_m3pm3
		//Note: 
		beC->by_key(DataDrawer_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m") = beC->by_key(DataDrawer_ID, DataFolder_ID, "Evapotranspiration_Depth_m") * (beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_FieldCapacity_m3pm3") - beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_MoistureInitial_m3pm3"));
	}
	//Storage_SoilEvapZone_TS_0th_m (m) computed using HydroPlusConfig.xml inputs to obtain exact initial condition, not end of time step condition
	beC->by_key(DataDrawer_ID, DataFolder_ID, "Storage_SoilEvapZone_TS_0th_m") = (beC->by_key(DataDrawer_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_Max_m") - beC->by_key(DataDrawer_ID, DataFolder_ID, "StorageDeficit_FieldCapacity_SoilEvapZone_TS_first_m"));

	//Catchment variables updated
	//If (Type is BulkArea) or (Type not BulkArea and Flag_Exfiltration_to_Catchment is 1), then sum area draining to vadose zone shared by catchment
	//Note: Consider refactor for GI to add Vault storage area rather than Pervious cover area, given vault area can be larger than pervious area
	if ((beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") == "BulkArea") || (beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") != "BulkArea" && beC->by_key(DataDrawer_ID, DataFolder_ID, "Flag_Exfiltration_to_Catchment")== 1)) {
		//Catchment_PerviousArea_AffectingStorageDeficit_m2 (m2) contains entire catchment pervious area draining to vadose zone
		//Note: Catchment_PerviousArea_AffectingStorageDeficit_m2 influences the catchment variable, StorageDeficit_VadoseZone_m
		input->RepoDict["Catchment_PerviousArea_AffectingStorageDeficit_m2"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_m2") * beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousCover_frac");
	}

	//static bool isInitialized = false initializes to false only once per simulation
	static bool isInitialized = false;

	//If not isInitialized then at first data folder and initialize to 0.0
	if (!isInitialized) {
		input->RepoDict["Catchment_LeafAreaIndex_Tree_m2m2"] = 0.0;
		input->RepoDict["Catchment_LeafAreaIndex_SVeg_m2m2"] = 0.0;
		input->RepoDict["Catchment_TotalPerviousCover_frac"] = 0.0;
		input->RepoDict["Catchment_TotalImperviousCover_frac"] = 0.0;
		input->RepoDict["Catchment_TotalTreeCover_frac"] = 0.0;
		input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] = 0.0;
		input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"] = 0.0;
		input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] = 0.0;
		input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"] = 0.0;
		input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] = 0.0;
		input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] = 0.0;
		input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"] = 0.0;
		input->RepoDict["Catchment_DCIA_frac"] = 0.0;
		input->RepoDict["Catchment_InfiltExcessGovernedArea_frac"] = 0.0;
		input->RepoDict["Catchment_MacroPore_frac"] = 0.0;
		//isInitialized = true; ensures only entered once
		isInitialized = true;
	}

	//update CatchmentArea_m2 for SpatialBuffer with GI
	if (input->SimulationStringParams["Model_Selection"] == "SpatialBufferwGI") {
			input->SimulationNumericalParams["CatchmentArea_m2"] = input->RepoVecDict["Catchment_Type_Area_m2"][0] + input->RepoVecDict["Catchment_Type_Area_m2"][1];
	}

	//Create parameters for catchment average land cover fraction for StatisticalHydro simulations
	double 	ratio_FolderArea_to_CatchmentArea = beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_m2") / input->SimulationNumericalParams["CatchmentArea_m2"];
	input->RepoDict["Catchment_LeafAreaIndex_Tree_m2m2"] = input->InputXml["LeafAreaIndex_Tree_m2pm2"];
	input->RepoDict["Catchment_LeafAreaIndex_SVeg_m2m2"] = input->InputXml["LeafAreaIndex_SVeg_m2pm2"];
	input->RepoDict["Catchment_TotalPerviousCover_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousCover_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_TotalImperviousCover_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_TotalTreeCover_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCover_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_TreeCanopyCover_overPervious_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_TreeCanopyCover_overImpervious_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_ImperviousCover_noTreeCanopy_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_WaterCover_noTreeCanopy_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "WaterCover_noTreeCanopy_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_ShortVegCover_noTreeCanopy_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_SoilCover_noTreeCanopy_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_PermeablePavementCover_noTreeCanopy_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_DCIA_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "DirectlyConnectedImperviousArea_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_InfiltExcessGovernedArea_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "InfiltExcessGovernedArea_frac") * ratio_FolderArea_to_CatchmentArea;
	input->RepoDict["Catchment_MacroPore_frac"] += beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Macropore_frac") * ratio_FolderArea_to_CatchmentArea;
}


void BuildDataOrganizer::Check_HydroPlusConfig_Inputs(Inputs* input, CompactRagged* beC, string Directory_Input_CLArg, int MapPixel_ID, int DataFolder_ID)
{
	//If HydroPlusConfig Type is not BulkArea or another known Type, then abort program
	if ((beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "BulkArea") && (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "RainGarden") &&
		(beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "BioRetention") && (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "GreenRoof") &&
		(beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "RainBarrel") && (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "PermeablePavement") &&
		(beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "Swale") && (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "InfilTrench") &&
		(beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "RoofDisconnect")) {

		cout << "Warning: The HydroPlusConfig.xml has a variable for the Type element not known to the HydroPlus model." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: When i-Tree Hydro model does not find a known Type, it cannot allocate a water balance." << endl;
		cout << "Correction: In the HydroPlusConfig.xml file, set the 1st DataFolder Type = BulkArea, and for any GI folders to Type: BioRetention, GreenRoof, IniltTrench, PermeablePavement, RainGarden, RainBarrel, RoofDisconnect, or Swale." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//If BulkArea T0_m2ph and Q0_mph are less than zero, then abort program
	//Note: Consider refactor to place these terms in SimulationNumericalParams for catchment to have single value 
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "BulkArea" && (input->InputXml["Discharge_Subsurface_Initial_mph"] <= 0 ||
		input->InputXml["VadoseZone_Transmissivity_Max_m2ph"] <= 0 || input->InputXml["Parameter_m_KsatExpDecay"] <= 0 ||
		input->InputXml["Parameter_n_KsatPowerDecay"] <= 0)) {
		cout << "Warning: HydroPlusConfig.xml has values <= 0 Discharge_Subsurface_Initial_mph, VadoseZone_Transmissivity_Max_m2ph, Parameter_m_KsatExpDecay, or Parameter_n_KsatPowerDecay." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: When any of these parameters are zero or less there is unrealistic subsurface flow in the catchment." << endl;
		cout << "Correction: In the HydroPlusConfig.xml file, modify parameters such that they are greater than zero." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//Note: Control HydroPlusConfig.xml has DataFolder with Area_m2 = 0 or Type not BulkArea and Count_GI_Units = 0 then model will abort
	if (input->SimulationNumericalParams["CatchmentArea_m2"] <= 0.0 || beC->by_key(MapPixel_ID, DataFolder_ID, "Area_m2") <= 0.0 || beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "BulkArea" && beC->by_key(MapPixel_ID, DataFolder_ID, "Count_GI_Units") <= 0.0) {
		if (input->SimulationStringParams["Model_Selection"] != "SpatialBufferwGI") {
			cout << "Warning: HydroPlusConfig.xml has parameter CatchmentArea_m2 = 0 m2, Area_m2 = 0 m2, or Area_m2 * Count_GI_Units = 0 m2." << endl;
			cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
			cout << "Explanation: When the HydroPlusConfig.xml parameters provide no CatchmentArea_m2, Area_m2, or Area_m2 * Count_GI_Units it cannot balance water." << endl;
			cout << "Correction: In the HydroPlusConfig.xml file, modify parameters such that CatchmentArea_m2 and Area_m2 are > 0." << endl;
			cout << "Correction: In the HydroPlusConfig.xml file, if using green infrastructure, then ensure Count_GI_Units > 0." << endl;
			//Call abort function, which ends the HydroPlus.exe simulation
			abort();
		}
	}

	//Note: Control HydroPlusConfig.xml has DataFolder Type for GI with keys Surface_Berm_Height_m >0 & Surface_Porosity_m3pm3 = 0, then model will abort
	//Note: May need to relax this constraint for GI types without the use of surface layer Surface_Berm_Height_m
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "BulkArea" && beC->by_key(MapPixel_ID, DataFolder_ID, "Surface_Berm_Height_m") > 0.0 && beC->by_key(MapPixel_ID, DataFolder_ID, "Surface_Porosity_m3pm3") <= 0.0) {
		cout << "Warning: HydroPlusConfig.xml contains DataFolder Type for Green Infrastructure (GI), but parameter Surface_Berm_Height_m > 0 and parameter Surface_Porosity_m3pm3 = 0." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: When the HydroPlusConfig.xml parameter Surface_Porosity_m3pm3 = 0, there are no voids in the GI layer to receive runoff." << endl;
		cout << "Correction: In the HydroPlusConfig.xml file, either remove the DataFolder Type GI, or modify parameters such that Surface_Porosity_m3pm3 > 0." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//Note: Control HydroPlusConfig.xml has DataFolder Type for GI with keys Soil_Thickness_m > 0 & soil porosity = 0, then model will abort
	//Note: This control is addressed by control in this section ensuring Soil_SaturationPoint_m3pm3 < Soil_WiltingPoint_m3pm3

	//Note: Control HydroPlusConfig.xml has DataFolder Type for GI with keys Vault_Thickness_m > 0 & Vault_Porosity_m3pm3 = 0, then model will abort
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "BulkArea" && beC->by_key(MapPixel_ID, DataFolder_ID, "Vault_Thickness_m") > 0 && beC->by_key(MapPixel_ID, DataFolder_ID, "Vault_Porosity_m3pm3")<= 0.0) {
		cout << "Warning: HydroPlusConfig.xml contains DataFolder Type for Green Infrastructure (GI) with parameter Vault_Thickness_m > 0, but parameter Vault_Porosity_m3pm3 = 0." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: When the HydroPlusConfig.xml parameter Vault_Thickness_m > 0 and Vault_Porosity_m3pm3 = 0, there are no voids in the GI layer to receive runoff." << endl;
		cout << "Correction: In the HydroPlusConfig.xml file, either remove the DataFolder Type GI, or modify parameters such that Vault_Thickness_m = 0 or Vault_Porosity_m3pm3 > 0." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//Note: Control HydroPlusConfig.xml has DataFolder Type for GI PermeablePavement with keys Pavement_Thickness_m > 0 & Pavement_Porosity_m3pm3 = 0, then model will abort
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "PermeablePavement") {
		if (beC->by_key(MapPixel_ID, DataFolder_ID, "Pavement_Thickness_m") <= 0 || beC->by_key(MapPixel_ID, DataFolder_ID, "Pavement_Porosity_m3pm3") <= 0 ||
			beC->by_key(MapPixel_ID, DataFolder_ID, "Pavement_Drainage_Limit_m") <= 0) {
			cout << "Warning: HydroPlusConfig.xml contains DataFolder Type for Permeable Pavement with parameters Pavement_Thickness_m, Pavement_Porosity_m3pm3, or Pavement_Drainage_Limit_m = 0." << endl;
			cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
			cout << "Explanation: When the HydroPlusConfig.xml parameter Pavement_Thickness_m, Pavement_Porosity_m3pm3, or Pavement_Drainage_Limit_m = 0, the model cannot balance water." << endl;
			cout << "Correction: In the HydroPlusConfig.xml file, modify parameters such that Pavement_Thickness_m, Pavement_Porosity_m3pm3, and Pavement_Drainage_Limit_m > 0." << endl;
			//Call abort function, which ends the HydroPlus.exe simulation
			abort();
		}
		//InfiltExcessGovernedArea_frac defined to 1 for PermeablePavement to ensure GreenAmpt routine used with Pavement_HydraulicConductivity_mph
		//Note: Pavement_HydraulicConductivity_mph is reduced by clogging, and can go to zero; if InfiltExcessGovernedArea_frac = 0 this constraint bypassed
		beC->by_key(MapPixel_ID, DataFolder_ID, "InfiltExcessGovernedArea_frac") = 1;
	}

	//If Control HydroPlusConfig.xml has Type GreenRoof, InfilTrench, RainBarrel, RoofDisconnect, but Vault_Thickness_m or Vault_Porosity_m3pm3 <= 0, then model will abort
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "GreenRoof" || beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "InfilTrench" ||
		beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "RainBarrel" || beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "RoofDisconnect") {
		//Note: Control HydroPlusConfig.xml has DataFolder Type for GI with storage layer and keys Vault_Thickness_m <= 0, then model will abort
		if (beC->by_key(MapPixel_ID, DataFolder_ID, "Vault_Thickness_m") <= 0 || beC->by_key(MapPixel_ID, DataFolder_ID, "Vault_Porosity_m3pm3")<= 0.0) {
			cout << "Warning: HydroPlusConfig.xml contains DataFolder Type " << beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") << "with parameter Vault_Thickness_m or parameter Vault_Porosity_m3pm3 = 0." << endl;
			cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
			cout << "Explanation: When the HydroPlusConfig.xml parameter Vault_Thickness_m or Vault_Porosity_m3pm3 = 0, the model cannot balance water." << endl;
			cout << "Correction: In the HydroPlusConfig.xml file, modify parameters such that Vault_Thickness_m and Vault_Porosity_m3pm3 > 0." << endl;
			if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "RoofDisconnect") { cout << "... Vault layer receives discharge from downspout." << endl; }
			//Call abort function, which ends the HydroPlus.exe simulation
			abort();
		}
	}

	//Note: Control HydroPlusConfig.xml parameters for Swale; swales are expected to have Surface_Outlet_BottomWidth_m > 0 for drainage 
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "Swale") {
		//Surface_BottomWidth_Min_m (m) set to a minimum surface width, overriding HydroPlusConfig.xml inputs; if used create cout statement
		double Surface_BottomWidth_Min_m = 0.05;
		if (beC->by_key(MapPixel_ID, DataFolder_ID, "Surface_Outlet_BottomWidth_m") < Surface_BottomWidth_Min_m) {
			cout << "Warning: For GI device Swale the HydroPlusConfig.xml input value of Surface_Outlet_BottomWidth_m was changed." << endl;
			cout << "Warning adjustment: Surface_Outlet_BottomWidth_m was increased from " << beC->by_key(MapPixel_ID, DataFolder_ID, "Surface_Outlet_BottomWidth_m") << " to " << Surface_BottomWidth_Min_m << "." << endl;
			cout << "Warning explained: The GI device Swale should have a Surface_Outlet_BottomWidth_m > 0 to allow outflow." << endl;

			//Surface_Outlet_BottomWidth_m for Swale is redefined to maximum of HydroPlusConfig.xml input or Surface_BottomWidth_Min_m to allow outflow
			beC->by_key(MapPixel_ID, DataFolder_ID, "Surface_Outlet_BottomWidth_m") = MAX(beC->by_key(MapPixel_ID, DataFolder_ID, "Surface_Outlet_BottomWidth_m"), Surface_BottomWidth_Min_m);
		}
	}

	//Note: Control HydroPlusConfig.xml parameter for exfiltration to catchment soils and possible upwelling of groundwater
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "BulkArea" && beC->by_key(MapPixel_ID, DataFolder_ID, "Flag_Exfiltration_to_Catchment")!= 0 &&
		beC->by_key(MapPixel_ID, DataFolder_ID, "Flag_Exfiltration_to_Catchment")!= 1) {
		cout << "Warning: HydroPlusConfig.xml contains an illogical Flag_Exfiltration_to_Catchment parameter." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: When the HydroPlusConfig.xml Flag_Exfiltration_to_Catchment parameter is illogical, the model cannot balance water." << endl;
		cout << "Correction: In the HydroPlusConfig.xml file, ensure Flag_Exfiltration_to_Catchment is 0 or 1." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//Note: Control HydroPlusConfig.xml parameter for exfiltration to catchment soils and possible decay of exfiltration rate
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") != "BulkArea" && beC->by_key(MapPixel_ID, DataFolder_ID, "Flag_Exfiltration_to_Catchment")== 1 &&
		beC->by_key(MapPixel_ID, DataFolder_ID, "Exfiltration_Limit_m") <= 0) {
		cout << "Warning: HydroPlusConfig.xml contains an illogical Exfiltration_Limit_m parameter." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: When the HydroPlusConfig.xml Flag_Exfiltration_to_Catchment = 1 and Exfiltration_Limit_m parameter = 0, the model cannot balance water." << endl;
		cout << "Correction: In the HydroPlusConfig.xml file, ensure Exfiltration_Limit_m is > 0." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}
	//Note: Control HydroPlusConfig.xml parameters for soil moisture, ensuring they are in proper sequence
	//Note: Consider refactor to allow Soil_WiltingPoint_m3pm3 > Soil_MoistureInitial_m3pm3, updating calculation of Storage_GI_Soil_m3, Storage_GI_Soil_Max_m3, Storage_GI_Soil_Max_Potential_m3
	//Note: Users can set Soil_WiltingPoint_m3pm3 to 0 to allow Soil_MoistureInitial_m3pm3 to reach 0
	if (beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_WiltingPoint_m3pm3") > beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_FieldCapacity_m3pm3") ||
		beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_FieldCapacity_m3pm3") > beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_SaturationPoint_m3pm3") ||
		beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_MoistureInitial_m3pm3") > beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_SaturationPoint_m3pm3") ||
		beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_WiltingPoint_m3pm3") > beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_MoistureInitial_m3pm3")) {
		cout << "MapPixel_ID " << MapPixel_ID << "DataFolder_ID " << DataFolder_ID << "Soil_MoistureInitial_m3pm3 " << beC->by_key(MapPixel_ID, DataFolder_ID, "Soil_MoistureInitial_m3pm3") << endl;
		cout << "Warning: HydroPlusConfig.xml contains illogical soil moisture parameters." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: When the HydroPlusConfig.xml soil moisture parameters are illogical, the model cannot balance water." << endl;
		cout << "Correction: In the HydroPlusConfig.xml file, ensure Soil_WiltingPoint_m3pm3 < Soil_FieldCapacity_m3pm3 < Soil_SaturationPoint_m3pm3 and Soil_WiltingPoint_m3pm3 <= Soil_MoistureInitial_m3pm3 <= Soil_SaturationPoint_m3pm3." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}
	//If BlockGroup_ID is zero and Flag_PrintBlockGroupDailyAndHourly_str != "0" then BlockGroup output is expected by missing blockgroup.asc input
	if (input->BlockGroup_ID.size() <= 0 && input->Flag_PrintBlockGroupDailyAndHourly_str != "0") {
		cout << "Warning: HydroPlusConfig.xml element PrintBlockGroupDailyAndHourly is > 0 but input folder has no blockgroup.asc." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: When the HydroPlusConfig.xml indicates block group analysis, the model needs a blockgroup.asc." << endl;
		cout << "Correction: In the HydroPlusConfig.xml file, change PrintBlockGroupDailyAndHourly to 0, or provide a blockgroup.asc." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}
	//If HydroPlusConfig.xml parameter Flag_CompareToObservedRunoff is not set to NoCalibration, then check if Runoff_Observed_for_Calibration.csv is provided
	//Note: HydroPlusConfig.xmls element Flag_CompareToObservedRunoff can equal 0, 1 (routed runoff), or 2 (unrouted runoff)
	if (input->SimulationNumericalParams["Flag_CompareToObservedRunoff"] != 0) {
		//Qobs_file created as string combination of Directory_Input_CLArg + "Runoff_Observed_for_Calibration.csv, where double backslash needed to get beyond escape character
		string Qobs_file = Directory_Input_CLArg + "Runoff_Observed_for_Calibration.csv";
		//readQobs created as part of fstream, defined as the Directory_Input_CLArg and file name for Runoff_Observed_for_Calibration.csv
		ifstream readQobs(Qobs_file);
		//if readQobs does not exist, alert user
		if (!readQobs) {
			cout << "Warning: The input file Runoff_Observed_for_Calibration.csv is missing." << endl;
			cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
			cout << "Explanation: Without observed flow data, the model cannot calibrate." << endl;
			cout << "Correction: Provide a Runoff_Observed_for_Calibration.csv file or set the HydroPlusConfig.xml element Flag_CompareToObservedRunoff = 0." << endl;
			//Call abort function, which ends the HydroPlus.exe simulation
			abort();
		}
	}

	//If Height_Sensor_Wind_m is < 2 then working with unusual data
	if (input->SimulationNumericalParams["Height_Sensor_Wind_m"] < 2) {
		cout << "Warning: HydroPlusConfig.xml element Height_Sensor_Wind_m is not appropriate." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: The HydroPlus model is designed for Height_Sensor_Wind_m of 2 to 10 m." << endl;
		cout << "Correction: Provide a reasonable Height_Sensor_Wind_m value in the DataFolder." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//If Height_Sensor_Tair_m is < 1 then working with unusual data
	if (input->SimulationNumericalParams["Height_Sensor_Tair_m"] < 1) {
		cout << "Warning: HydroPlusConfig.xml element Height_Sensor_Tair_m is not appropriate." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: The HydroPlus model is designed for Height_Sensor_Tair_m of 1 to 10 m." << endl;
		cout << "Correction: Provide a reasonable Height_Sensor_Tair_m value in the DataFolder." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//If Height_Sensor_Wind_m is < zero then working with unusual data
	if (beC->by_key_str(MapPixel_ID, DataFolder_ID, "Type") == "BulkArea" && (input->InputXml["Height_Avg_TreeCover_m"] <= 0 || input->InputXml["Height_Avg_SVegCover_m"] <= 0)) {
		cout << "Warning: HydroPlusConfig.xml elements Height_Avg_TreeCover_m and/or Height_Avg_SVegCover_m are <= 0." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: The HydroPlus model requires Height_Avg_TreeCover_m and Height_Avg_SVegCover_m > 0." << endl;
		cout << "Correction: Set Height_Avg_TreeCover_m and Height_Avg_SVegCover_m > 0 in the DataFolder." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}

	//If Flag_Scenario_CoolAir_Irrigate is > 0 then check if other terms are provided
	if (input->SimulationScenarios["Flag_Scenario_CoolAir_Irrigate"] > 0 &&
		(input->SimulationScenarios.count("Scenario_CoolAir_Irrigate_Tair_K") == 0 ||
			input->SimulationScenarios.count("Scenario_CoolAir_Irrigate_Day_or_Night") == 0 ||
			input->SimulationScenarios.count("Scenario_CoolAir_Irrigate_MaxPerDay") == 0 ||
			input->SimulationScenarios.count("Scenario_CoolAir_Irrigate_LandCover_Class") == 0)
		) {
		cout << "Warning: HydroPlusConfig.xml element missing needed fields when Flag_Scenario_CoolAir_Irrigate is 1." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: The HydroPlusConfig.xml needs the following elements:" << endl;
		cout << "  Scenario_CoolAir_Irrigate_Tair_K" << endl;
		cout << "  Scenario_CoolAir_Irrigate_Day_or_Night" << endl;
		cout << "  Scenario_CoolAir_Irrigate_MaxPerDay" << endl;
		cout << "  Scenario_CoolAir_Irrigate_LandCover_Class" << endl;
		cout << "Correction: Place the above elements into the HydroPlusConfig.xml; 0 values will work." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}
	//If Flag_Scenario_CoolAir_NoTreeTranspiration is > 0 then check if other terms are provided
	if (input->SimulationScenarios["Flag_Scenario_CoolAir_NoTreeTranspiration"] > 0 &&
		input->SimulationScenarios.count("Scenario_CoolAir_NoTreeTranspiration_LandCover_Class") == 0) {
		cout << "Warning: HydroPlusConfig.xml element missing needed fields when Flag_Scenario_CoolAir_NoTreeTranspiration is 1." << endl;
		cout << "Aborting: This warning triggers the HydroPlus simulation to abort." << endl;
		cout << "Explanation: The HydroPlusConfig.xml needs the following elements:" << endl;
		cout << "  Scenario_CoolAir_NoTreeTranspiration_LandCover_Class" << endl;
		cout << "Correction: Place the above elements into the HydroPlusConfig.xml; 0 values will work." << endl;
		//Call abort function, which ends the HydroPlus.exe simulation
		abort();
	}
}

//Catchment_CoverData_FolderType function computes GI variable weighted averages for areas
//Note: Area weighted averages require use of folder fractional terms and Area_m2, which can be computed during initial loop through folders
void BuildDataOrganizer::Catchment_CoverData_FolderType(Inputs* input, CompactRagged* beC, int DataDrawer_ID, int DataFolder_ID, int Folder_Type_ID)
{
	//required_size is dynamically updated with FolderType_List.size()
	size_t required_size = input->FolderType_List.size();

	vector<string> LandCover_Variables_keys = {
		"TotalPerviousCover_Type_m2",
		"TotalImperviousCover_Type_m2",
		"TotalTreeCover_Type_m2",
		"TreeCanopyCover_overPervious_Type_m2",
		"TreeCanopyCover_overImpervious_Type_m2",
		"ImperviousCover_noTreeCanopy_Type_m2",
		"WaterCover_noTreeCanopy_Type_m2",
		"ShortVegCover_noTreeCanopy_Type_m2",
		"SoilCover_noTreeCanopy_Type_m2",
		"PermeablePavementCover_noTreeCanopy_Type_m2",
		"DCIA_Type_m2",
		"InfiltExcessGovernedArea_Type_m2",
		"MacroPore_Type_m2"
	};
	//For LandCover_Variables_key in LandCover_Variables_keys
	for (const auto& LandCover_Variables_key : LandCover_Variables_keys) {
		//If RepoVecDict[LandCover_Variables_key].size() < required_size then add new index
		if (input->RepoVecDict[LandCover_Variables_key].size() < required_size) {
			//RepoVecDict[LandCover_Variables_key].resize(required_size, 0.0); increased index
			input->RepoVecDict[LandCover_Variables_key].resize(required_size, 0.0);
		}
	}

	//Folder_Area_m2 = beC->by_key(MapPixel_ID, DataFolder_ID, "Area_m2"); actively defined for folder prior to call
	double Folder_Area_m2 = beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_m2");

	//TotalPerviousCover_Type_m2 (m2) += PerviousCover_frac (frac) * Folder_Area_m2 (m2); accumulating the amount in each folder
	//Note: RepoVecDict variable contains catchment total of Folder_Type_ID specific variables, e.g., BulkArea or GreenInfrastructure
	input->RepoVecDict["TotalPerviousCover_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "PerviousCover_frac") * Folder_Area_m2;
	input->RepoVecDict["TotalImperviousCover_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_frac") * Folder_Area_m2;
	input->RepoVecDict["TotalTreeCover_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCover_frac") * Folder_Area_m2;
	input->RepoVecDict["TreeCanopyCover_overPervious_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overPervious_frac") * Folder_Area_m2;
	input->RepoVecDict["TreeCanopyCover_overImpervious_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "TreeCanopyCover_overImpervious_frac") * Folder_Area_m2;
	input->RepoVecDict["ImperviousCover_noTreeCanopy_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "ImperviousCover_noTreeCanopy_frac") * Folder_Area_m2;
	input->RepoVecDict["WaterCover_noTreeCanopy_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "WaterCover_noTreeCanopy_frac") * Folder_Area_m2;
	input->RepoVecDict["ShortVegCover_noTreeCanopy_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "ShortVegCover_noTreeCanopy_frac") * Folder_Area_m2;
	input->RepoVecDict["SoilCover_noTreeCanopy_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "SoilCover_noTreeCanopy_frac") * Folder_Area_m2;
	input->RepoVecDict["PermeablePavementCover_noTreeCanopy_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "PermeablePavementCover_noTreeCanopy_frac") * Folder_Area_m2;
	input->RepoVecDict["DCIA_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "DirectlyConnectedImperviousArea_frac") * Folder_Area_m2;
	input->RepoVecDict["InfiltExcessGovernedArea_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "InfiltExcessGovernedArea_frac") * Folder_Area_m2;
	input->RepoVecDict["MacroPore_Type_m2"][Folder_Type_ID] += beC->by_key(DataDrawer_ID, DataFolder_ID, "Soil_Macropore_frac") * Folder_Area_m2;
}

//Prepare_GI_PollutantRemoval function computes GI variable weighted averages for fractions
//Note: Fractional weighted averages require use of Catchment_Type_Area_m2, which is first created by summing Area_m2 for all folders
void BuildDataOrganizer::Prepare_GI_PollutantRemoval(DataOrganizer* organizer, Inputs* input, CompactRagged* beC)
{

	string Name_Removal_Rate_Pollutant_frac;
	string Name_Removal_Rate_Pollutant_percent;
	//For Loop through pollutant names to write output file header; length of For Loop is Pollutant_Name.size()
	//Note: Pollutant_Name vector used below are from Pollutants.csv, read in Inputs.cpp into vector 
	for (int pollutant_ID = 0; pollutant_ID < input->Pollutant_Name.size(); pollutant_ID++) {
		//Create string to represent variable associated with Pollutant_Name
		Name_Removal_Rate_Pollutant_frac = "Removal_Rate_" + input->Pollutant_Name[pollutant_ID] + "_Avg_frac";
		//Name_Removal_Rate_Pollutant_frac reset to zero at start of simulation, MapPixel_ID equal to zero
		input->RepoDict[Name_Removal_Rate_Pollutant_frac] = 0;
	}

	//Loop through the DataDrawers, where the upper bound is based on the general DataDrawer attribute .size()
	//Note: DataDrawers[0] is first DataFolder in vector, which is the BulkArea in HydroPlusConfig.xml file
	//Note: DataDrawers vector size is determined when reading in the HydroPlusConfig.xml and other input data
	for (int DataDrawer_ID = 0; DataDrawer_ID < input->DataDrawers.size(); ++DataDrawer_ID) {

		//Loop through the DataFolders in each DataDrawer[DataDrawer_ID], upper bound indicated by .size()
		for (auto DataFolder_ID = 0; DataFolder_ID < input->DataDrawers[DataDrawer_ID].size(); ++DataFolder_ID) {

			//If HydroPlusConfig.xml Type not equal to BulkArea then prepare GreenInfrastructure Name_Removal_Rate_Pollutant_frac
			if (beC->by_key_str(DataDrawer_ID, DataFolder_ID, "Type") != "BulkArea" || input->SimulationStringParams["Model_Selection"] == "SpatialTemperatureHydro") {
				//Folder_Type_ID defined as one for GreenInfrastructure
				int Folder_Type_ID = 1;
				//Ratio_FolderTypeArea_to_CatchmentTypeArea (fraction) is ratio of folder Type Area_m2 and catchment area of folders with that Type
				double Ratio_FolderTypeArea_to_CatchmentTypeArea = beC->by_key(DataDrawer_ID, DataFolder_ID, "Area_m2") / input->RepoVecDict["Catchment_Type_Area_m2"][Folder_Type_ID];
				//For Loop through pollutant names to write output file header; length of For Loop is Pollutant_Name.size()
				//Note: Pollutant_Name vector used below are from Pollutants.csv, read in Inputs.cpp into vector 
				for (int pollutant_ID = 0; pollutant_ID < input->Pollutant_Name.size(); pollutant_ID++) {
					//Create string to represent variable associated with Pollutant_Name
					Name_Removal_Rate_Pollutant_frac = "Removal_Rate_" + input->Pollutant_Name[pollutant_ID] + "_Avg_frac";
					//Create string to represent variable associated with Pollutant_Name
					Name_Removal_Rate_Pollutant_percent = input->Pollutant_Name[pollutant_ID] + "_RemovalEfficiency_percent";
					//Removal_Rate_Pollutant_frac (fraction) is pollutant removal rate (%) multiplied by Ratio_Decimal_to_Percent; removal rate from HydroPlusConfig.xml
					double Removal_Rate_Pollutant_frac = beC->by_key(DataDrawer_ID, DataFolder_ID, Name_Removal_Rate_Pollutant_percent) * Ratio_Decimal_to_Percent;
					//RepoDict variable Name_Removal_Rate_Pollutant_frac is sum of Removal_Rate_Pollutant_frac * ratio_GIArea_to_CatchmentGIArea
					input->RepoDict[Name_Removal_Rate_Pollutant_frac] += Removal_Rate_Pollutant_frac * Ratio_FolderTypeArea_to_CatchmentTypeArea;
				}
			}
		}
	}
}
