Skip to content

Commit

Permalink
Debugging pump costs, well count calculations
Browse files Browse the repository at this point in the history
  • Loading branch information
mjprilliman committed Dec 27, 2024
1 parent d7efae3 commit 89fceab
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 8 deletions.
107 changes: 101 additions & 6 deletions shared/lib_geothermal.cpp
Original file line number Diff line number Diff line change
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,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));
Expand All @@ -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;
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
7 changes: 5 additions & 2 deletions ssc/cmod_geothermal_costs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand All @@ -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<ssc_number_t>(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<ssc_number_t>(indirect_pump_gathering_cost);

//OM Cost calculations
/*
double unit_plant = as_double("gross_output");
Expand Down

0 comments on commit 89fceab

Please sign in to comment.