diff --git a/shared/lib_geothermal.cpp b/shared/lib_geothermal.cpp index ea0e47191..7b4e9128d 100644 --- a/shared/lib_geothermal.cpp +++ b/shared/lib_geothermal.cpp @@ -1513,8 +1513,71 @@ double CGeothermalAnalyzer::flowRateTotal(void) { } } // lbs per hour, all wells +void CGeothermalAnalyzer::WellCountDecisionTable(void) +{ + int well_stim = mo_geo_in.md_WellsStimulated; //0 - injection only, 1 - production only, 2 - both + double production_stim_well = 0; //Column A + double injection_stim_well = 0; //Column B + double stim_well = 0; //Column C + double SWDDE = mo_geo_in.md_ExplorationWellsProd; + switch (well_stim) { + case 0: + if (mo_geo_in.me_rt == HYDROTHERMAL) { + production_stim_well = SWDDE; + injection_stim_well = 0; + } + else if (SWDDE >= 1.0) { + production_stim_well = SWDDE - 1; + injection_stim_well = 1; + } + else if (SWDDE > 0.0) { + production_stim_well = 0; + injection_stim_well = SWDDE; + } + else { + production_stim_well = 0; + injection_stim_well = 0; + } + case 1: + if (mo_geo_in.me_rt == HYDROTHERMAL) { + production_stim_well = SWDDE; + injection_stim_well = 0; + } + else if (SWDDE >= 1.0) { + production_stim_well = 1; + injection_stim_well = SWDDE - 1; + } + else if (SWDDE > 0.0) { + production_stim_well = 0; + injection_stim_well = SWDDE; + } + else { + production_stim_well = 0; + injection_stim_well = 0; + } + case 2: + if (mo_geo_in.me_rt == HYDROTHERMAL) { + production_stim_well = SWDDE; + injection_stim_well = 0; + } + else if (SWDDE > 0.0) { + production_stim_well = SWDDE/2; + injection_stim_well = SWDDE/2; + } + else { + production_stim_well = 0; + injection_stim_well = 0; + } + } + mp_geo_out->ProdWellsExploration = production_stim_well; + mp_geo_out->InjWellsExploration = injection_stim_well; +} + double CGeothermalAnalyzer::GetNumberOfWells(void) { + WellCountDecisionTable(); + bool inj_wells_stimulated = (mo_geo_in.md_WellsStimulated == 0 || mo_geo_in.md_WellsStimulated == 2); + bool prod_wells_stimulated = (mo_geo_in.md_WellsStimulated == 1 || mo_geo_in.md_WellsStimulated == 2); if (mo_geo_in.me_cb == NUMBER_OF_WELLS) { mp_geo_out->md_NumberOfWells = mo_geo_in.md_NumberOfWells; @@ -1534,10 +1597,12 @@ double CGeothermalAnalyzer::GetNumberOfWells(void) mp_geo_out->md_PumpWorkWattHrPerLb = GetPumpWorkWattHrPerLb(); mp_geo_out->md_NumberOfWells = mo_geo_in.md_DesiredSalesCapacityKW / netCapacityPerWell; if (mp_geo_out->md_NumberOfWells < 0) mp_geo_out->md_NumberOfWells = 0; - mp_geo_out->md_NumberOfWellsProdExp = mp_geo_out->md_NumberOfWells - mo_geo_in.md_ExplorationWellsProd - mp_geo_out->md_FailedWells; + mp_geo_out->md_NumberOfWellsProdExp = (mp_geo_out->md_NumberOfWells > mp_geo_out->ProdWellsExploration) ? mp_geo_out->md_NumberOfWells - mo_geo_in.md_ExplorationWellsProd : 0.0; mp_geo_out->md_NumberOfWellsProdDrilled = mp_geo_out->md_NumberOfWellsProdExp / (1 - (1 - mo_geo_in.md_StimSuccessRate) * (1 - mo_geo_in.md_DrillSuccessRate)); double num_prod_wells_successful = mp_geo_out->md_NumberOfWellsProdDrilled * mo_geo_in.md_DrillSuccessRate; double num_prod_wells_failed = mp_geo_out->md_NumberOfWellsProdDrilled * (1 - mo_geo_in.md_DrillSuccessRate); + //2. # of Injection Wells Required = # successful injection wells required in drilling phase + # successful injection wells drilled in exploration phase + double inj_flow = flowRatePerWell() * mp_geo_out->md_NumberOfWells; if (mo_geo_in.me_ct == FLASH) inj_flow -= inj_flow * (waterLoss() / 1000.0); double failed_prod_wells_inj = mp_geo_out->md_NumberOfWellsProdDrilled - num_prod_wells_successful; @@ -1549,20 +1614,49 @@ double CGeothermalAnalyzer::GetNumberOfWells(void) double prod_failed_inj_rate = (mo_geo_in.md_FailedProdFlowRatio * mo_geo_in.md_ReservoirDeltaPressure) * (mo_geo_in.md_InjWellPressurePSI + geothermal::MetersToFeet(GetResourceDepthM()) * InjectionDensity() / 144.0 + (pressure_well_head) - mo_geo_in.md_ProdWellFriction * pow(mo_geo_in.md_FailedProdFlowRatio, 2) - pressureHydrostaticPSI()); - double inj_failed_inj_rate = (mo_geo_in.md_FailedProdFlowRatio * mo_geo_in.md_ReservoirDeltaPressure) * + double inj_failed_inj_rate = (mo_geo_in.md_FailedProdFlowRatio > 0) ? (mo_geo_in.md_FailedProdFlowRatio * mo_geo_in.md_ReservoirDeltaPressure) * (mo_geo_in.md_InjWellPressurePSI + geothermal::MetersToFeet(GetResourceDepthM()) * InjectionDensity() / 144.0 + (pressure_well_head) - - mo_geo_in.md_InjWellFriction * pow(mo_geo_in.md_FailedProdFlowRatio, 2) - pressureHydrostaticPSI()); + mo_geo_in.md_InjWellFriction * pow(mo_geo_in.md_FailedProdFlowRatio, 2) - pressureHydrostaticPSI()) * mo_geo_in.md_FailedProdFlowRatio * mo_geo_in.md_ReservoirDeltaPressure : 0.0; double inj_rate_failed_prod_wells = MIN(prod_failed_inj_rate, flowRatePerWell()); //Injectivity of failed production well? double inj_rate_failed_inj_wells = MIN(inj_failed_inj_rate, flowRatePerWell()); + double inj_rate_successful_inj_wells = flowRatePerWell() / mo_geo_in.md_RatioInjectionToProduction; + double num_failed_prod_wells_inj = (mo_geo_in.md_FailedProdFlowRatio > 0) ? mp_geo_out->md_NumberOfWellsProdDrilled - num_prod_wells_successful : 0.0; + double successful_inj_wells_required_drilling = (inj_flow - (num_failed_prod_wells_inj * prod_failed_inj_rate)) / (inj_rate_successful_inj_wells + (inj_rate_failed_inj_wells * (1 / (mo_geo_in.md_DrillSuccessRate) - 1))); + double successful_inj_wells_exploration = mp_geo_out->InjWellsExploration; + double num_injection_wells_required = successful_inj_wells_required_drilling + successful_inj_wells_exploration; mp_geo_out->md_NumberOfWellsInj = (inj_flow - (failed_prod_wells_inj * inj_rate_failed_prod_wells)) / (flowPerWellInj + inj_rate_failed_inj_wells * (1 / (mo_geo_in.md_DrillSuccessRate) - 1)); - mp_geo_out->md_NumberOfWellsInjDrilled = (1 / mo_geo_in.md_DrillSuccessRate) * mp_geo_out->md_NumberOfWellsInj; + mp_geo_out->md_NumberOfWellsInjDrilled = (1 / mo_geo_in.md_DrillSuccessRate) * successful_inj_wells_required_drilling + successful_inj_wells_exploration; double num_inj_wells_successful = mp_geo_out->md_NumberOfWellsInjDrilled * mo_geo_in.md_DrillSuccessRate; double num_inj_wells_failed = mp_geo_out->md_NumberOfWellsInjDrilled * (1 - mo_geo_in.md_DrillSuccessRate); //mp_geo_out->md_NumberOfWellsInj = (mo_geo_in.md_DesiredSalesCapacityKW / (netBrineEffectiveness / 1000)) * (mp_geo_out->md_FractionGFInjected) / flowPerWellInj; mp_geo_out->md_InjPump_hp = ( (mp_geo_out->md_NumberOfWellsInj * flowPerWellInj * GetInjectionPumpWorkft()) / (60 * 33000) ) / mo_geo_in.md_GFPumpEfficiency; if (mo_geo_in.me_rt == EGS) { - mp_geo_out->md_NumberOfWellsProdExp = mp_geo_out->md_NumberOfWells - 8; - mp_geo_out->md_NumberOfWellsProdDrilled = mp_geo_out->md_NumberOfWellsProdExp / mo_geo_in.md_DrillSuccessRate; + //mp_geo_out->md_NumberOfWellsProdExp = mp_geo_out->md_NumberOfWells - 8; + if (mo_geo_in.md_WellsStimulated != 1) mp_geo_out->md_NumberOfWellsProdDrilled = mp_geo_out->md_NumberOfWellsProdExp / (mo_geo_in.md_DrillSuccessRate); + else { + double failed_prod_well_stimulations = 0; + double successful_prod_well_stimulations = 0; + if (mo_geo_in.md_WellsStimulated == 3) { + failed_prod_well_stimulations = 0; + successful_prod_well_stimulations = 0; + } + else { + failed_prod_well_stimulations = mp_geo_out->md_NumberOfWellsProdExp * (1 / mo_geo_in.md_StimSuccessRate - 1); + successful_prod_well_stimulations = mp_geo_out->md_NumberOfWellsProdExp; + } + mp_geo_out->md_NumberOfWellsProdDrilled = (failed_prod_well_stimulations + successful_prod_well_stimulations) / mo_geo_in.md_DrillSuccessRate; + + } + double inj_wells_drilled = 0; + if (inj_wells_stimulated) { + inj_wells_drilled = mp_geo_out->md_NumberOfWellsInj / (mo_geo_in.md_DrillSuccessRate * mo_geo_in.md_StimSuccessRate); + } + else { + inj_wells_drilled = mp_geo_out->md_NumberOfWellsInj / (mo_geo_in.md_DrillSuccessRate); + } + mp_geo_out->md_NumberOfWellsInjDrilled = inj_wells_drilled; + //mp_geo_out->md_NumberOfWellsProdDrilled = mp_geo_out->md_NumberOfWellsProdExp / mo_geo_in.md_DrillSuccessRate; + /* num_prod_wells_failed = mp_geo_out->md_NumberOfWellsProdExp / mo_geo_in.md_DrillSuccessRate * (1 - mo_geo_in.md_DrillSuccessRate); num_prod_wells_successful = mp_geo_out->md_NumberOfWellsProdExp; inj_flow = flowRatePerWell() * mp_geo_out->md_NumberOfWells * (1 + (1 / (1 - 0.05) - 1)); @@ -1572,6 +1666,7 @@ double CGeothermalAnalyzer::GetNumberOfWells(void) num_inj_wells_failed = mp_geo_out->md_NumberOfWellsInjDrilled * mo_geo_in.md_DrillSuccessRate; double inj_wells_stim = successful_inj_wells_expl / mo_geo_in.md_StimSuccessRate; double failed_stim_wells = inj_wells_stim - successful_inj_wells_expl; + */ } if (mp_geo_out->md_NumberOfWellsInj < 0) mp_geo_out->md_NumberOfWellsInj = 0; diff --git a/shared/lib_geothermal.h b/shared/lib_geothermal.h index 9dcdff2cc..8e6d4759f 100644 --- a/shared/lib_geothermal.h +++ b/shared/lib_geothermal.h @@ -107,6 +107,7 @@ struct SGeothermal_Inputs double md_ProdWellFriction; double md_NumberOfWells; // entered or calculated, depending on 'cb' double md_NumberofWellsInj; + int md_WellsStimulated; // 0 - Injection only, 1 - Production only, 2 - both, 3 - neither double md_PlantEfficiency; // not in GETEM - essentially the ratio of plant brine effectiveness to max possible brine effectiveness double md_TemperatureDeclineRate; // '% per year, 3% is default double md_MaxTempDeclineC; // degrees C, default = 30 @@ -181,6 +182,8 @@ struct SGeothermal_Outputs //Following list of variables used as inputs in cmod_geothermal_costs.cpp for calculating direct geothermal plant cost: double md_NumberOfWells; double md_NumberOfWellsProdExp; + double ProdWellsExploration; + double InjWellsExploration; double md_NumberOfWellsProdDrilled; double md_NumberOfWellsInjDrilled; double md_FailedWells; @@ -368,6 +371,7 @@ class CGeothermalAnalyzer double flowRatePerWell(void); // take Kg/second input and translate to lbs/hour double flowRateTotal(void); // flow rate per well * number of wells double GetNumberOfWells(void); + void WellCountDecisionTable(void); double GetPlantBrineEffectiveness(void); // turbine output diff --git a/ssc/cmod_geothermal_costs.cpp b/ssc/cmod_geothermal_costs.cpp index 9f3b5ab51..477343012 100644 --- a/ssc/cmod_geothermal_costs.cpp +++ b/ssc/cmod_geothermal_costs.cpp @@ -91,7 +91,7 @@ static var_info _cm_vtab_geothermal_costs[] = { { SSC_INPUT, SSC_NUMBER, "geotherm.cost.pump_geotherm.cost.pump_depth", "Pump depth", "ft", "", "GeoHourly", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "geotherm.cost.prod_req", "Number of production wells required", "", "", "GeoHourly", "", "", "" }, { SSC_INPUT, SSC_NUMBER, "pump_size_hp", "Production pump power", "hp", "", "GeoHourly", "", "", "" }, - { SSC_INPUT, SSC_NUMBER, "inj_size_hp", "Injection pump power", "hp", "", "GeoHourly", "", "", "" }, + { SSC_INPUT, SSC_NUMBER, "inj_pump_hp", "Injection pump power", "hp", "", "GeoHourly", "", "", "" }, // Outputs @@ -805,7 +805,7 @@ class cm_geothermal_costs : public compute_module if (pipe_diam == 0) pipe_diam = 12.5; else pipe_diam = 8.75; double pipe_outer_diam = pipe_diam + 2 * 0.375; //inches - double pipe_cost_per_foot = 0.4249 * pow(pipe_outer_diam, 2); -0.0472 * pipe_outer_diam + 40.683; + double pipe_cost_per_foot = 0.4249 * pow(pipe_outer_diam, 2) - 0.0472 * pipe_outer_diam + 40.683; double pipe_cost_per_foot_adj = pipe_cost_per_foot * steel_ppi[ppi_base_year]; double distance_plant_to_well = 1640.4; int resource_type = as_integer("resource_type"); @@ -814,6 +814,9 @@ class cm_geothermal_costs : public compute_module double gathering_cost_total = piping_cost_per_well * (num_prod_wells + num_inj_wells); assign("total_gathering_cost", var_data(static_cast(gathering_cost_total))); + double indirect_pump_gathering_cost = (total_pump_cost + gathering_cost_total) * (1.0 / (1 - 0.12) - 1); + assign("indirect_pump_gathering_cost", var_data(static_cast(indirect_pump_gathering_cost); + //OM Cost calculations /* double unit_plant = as_double("gross_output");