Skip to content

Commit

Permalink
Merge branch 'getem-pump-costs' into getem_costs
Browse files Browse the repository at this point in the history
  • Loading branch information
mjprilliman committed Jan 2, 2025
2 parents a655fb9 + d55411d commit 1a21115
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 18 deletions.
118 changes: 107 additions & 11 deletions shared/lib_geothermal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1158,24 +1158,24 @@ double CGeothermalAnalyzer::Gringarten()

double CGeothermalAnalyzer::RameyWellbore()
{
double alpharock = mo_geo_in.md_EGSThermalConductivity / (mo_geo_in.md_EGSRockDensity * mo_geo_in.md_EGSSpecificHeatConstant);
double alpharock = (mo_geo_in.md_EGSThermalConductivity) / (mo_geo_in.md_EGSRockDensity * mo_geo_in.md_EGSSpecificHeatConstant);
double time = 0;
double working_temp = md_WorkingTemperatureC;
if (mp_geo_out->ElapsedHours < 0.1) {
time = 744 * 3600;
time = 8760 * 3600;
working_temp = GetResourceTemperatureC();
}
else {
time = mp_geo_out->ElapsedHours * 3600; //elapsed time (s)
working_temp = md_WorkingTemperatureC;
}
double utilfactor = 1.0; //capacity factor?
double avg_gradient = 2 / GetResourceDepthM(); //local average geothermal gradient
double framey = -1.0 * log(1.1 * (0.3048 * (mo_geo_in.md_DiameterProductionWellInches / (2 * 12)) / sqrt(4.0 * alpharock * time * utilfactor))) - 0.29;
double avg_gradient = (GetResourceTemperatureC() - 11.6) / GetResourceDepthM(); //local average geothermal gradient
double framey = -1.0 * log(1.1 * (0.3048 * (mo_geo_in.md_DiameterPumpCasingInches / (2 * 12)) / sqrt(4.0 * alpharock * time * utilfactor))) - 0.29;
double c_w = geothermal::EGSSpecificHeat(working_temp);
double rameyA = mo_geo_in.md_ProductionFlowRateKgPerS * c_w * framey / (2 * physics::PI * mo_geo_in.md_EGSThermalConductivity);
double ProdTempDrop = -1.0 * ((GetResourceTemperatureC() - working_temp) - avg_gradient * (GetResourceDepthM() - rameyA) + (working_temp - avg_gradient * rameyA - GetResourceTemperatureC()) * exp(-GetResourceDepthM() / rameyA));
return ProdTempDrop;
return (isfinite(ProdTempDrop)) ? ProdTempDrop : 0.0;
}

double CGeothermalAnalyzer::DT_prod_well(double prod_well_choice)
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -1549,20 +1614,50 @@ 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()) : 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_NumberOfWellsInj = inj_flow / inj_rate_successful_inj_wells - successful_inj_wells_exploration;
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));
Expand All @@ -1572,6 +1667,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;
Expand Down
4 changes: 4 additions & 0 deletions shared/lib_geothermal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion ssc/cmod_geothermal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ class cm_geothermal : public compute_module

// assign values for UI results
assign("num_wells_getem_output", var_data((ssc_number_t)geo_outputs.md_NumberOfWells));
assign("num_wells_getem_inj", var_data((ssc_number_t)geo_outputs.md_NumberOfWellsInj));
assign("num_wells_getem_inj", var_data((ssc_number_t)geo_outputs.md_NumberOfWellsInjDrilled));
assign("plant_brine_eff", var_data((ssc_number_t)geo_outputs.md_PlantBrineEffectiveness));
assign("pump_watthr_per_lb", var_data((ssc_number_t)geo_outputs.md_PumpWorkWattHrPerLb));
assign("pumpwork_prod", var_data((ssc_number_t)geo_outputs.md_pumpwork_prod));
Expand Down
Loading

0 comments on commit 1a21115

Please sign in to comment.