Skip to content

Commit

Permalink
use module temp in place of cell temp if not using sapm
Browse files Browse the repository at this point in the history
  • Loading branch information
alorenzo175 committed Mar 12, 2021
1 parent dc8d413 commit 6d7a3c7
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 9 deletions.
50 changes: 43 additions & 7 deletions api/solarperformanceinsight_api/compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,9 +509,17 @@ def compare_expected_and_actual(job: models.StoredJob, si: storage.StorageInterf
save_results_to_db(job.object_id, result_list, si)


def _zero_div(a, b):
out = a / b
a_almost_zero = abs(a) < 1e-16
nans = pd.isnull(out) # nan when 0 / 0, a > 0 /0 => inf
out[a_almost_zero & nans] = 0.0
return out


def _temp_factor(gamma, t_ref, t_actual):
t0 = 25.0
return (1 - gamma * (t_actual - t0)) / (1 - gamma * (t_ref - t0))
return _zero_div(1 - gamma * (t_actual - t0), 1 - gamma * (t_ref - t0))


def _get_mc_dc(mcresult: ModelChainResult, num_arrays: int) -> pd.DataFrame:
Expand All @@ -523,6 +531,26 @@ def _get_mc_dc(mcresult: ModelChainResult, num_arrays: int) -> pd.DataFrame:
return pd.DataFrame({"performance": out}) # type: ignore


def _get_temp(
weather_df: Tuple[pd.DataFrame, ...],
cell_temp: Tuple[pd.Series, ...],
arrays: List[models.PVArray],
tshift: dt.timedelta,
) -> Tuple[pd.Series, ...]:
out = []
for df, ct, arr in zip(weather_df, cell_temp, arrays):
if (
not isinstance(
arr.temperature_model_parameters, models.SAPMTemperatureParameters
)
and "module_temperature" in df.columns
):
out.append(df["module_temperature"].shift(freq=tshift)) # type: ignore
else:
out.append(ct)
return tuple(out)


def _calculate_weather_adjusted_predicted_performance(
job: models.StoredJob, si: storage.StorageInterface
) -> Tuple[List[DBResult], pd.Series]:
Expand Down Expand Up @@ -589,7 +617,8 @@ def _calculate_weather_adjusted_predicted_performance(
# instead of full modelchain calculation.
# since it sets class properties, copy for the actuals calculations
chain_actual = deepcopy(chain)
pac0 = job.definition.system_definition.inverters[i].inverter_parameters._pac0
inv = job.definition.system_definition.inverters[i]
pac0 = inv.inverter_parameters._pac0
num_arrays = len(chain.system.arrays)
gammas = [
arr._gamma for arr in job.definition.system_definition.inverters[i].arrays
Expand Down Expand Up @@ -624,16 +653,23 @@ def _calculate_weather_adjusted_predicted_performance(
chain_actual.results.total_irrad, chain_actual.results.effective_irradiance
)
# use cell temperature from the pvlib modelchain
# If air temp + wind speed or module temperature were supplied, they are
# converted to cell temperature via the array's temperature model
t_ref = chain.results.cell_temperature
t_actual = chain_actual.results.cell_temperature
# If air temp + wind speed were supplied, they are converted
# to cell temperature via the array's temperature model. If
# module_temperature was supplied and the temperature model is
# sapm, it is converted to cell_temperature, otherwise module
# temperature is used in place of cell_temperature
t_ref = _get_temp(
ref_weather, chain.results.cell_temperature, inv.arrays, tshift
)
t_actual = _get_temp(
actual_weather, chain_actual.results.cell_temperature, inv.arrays, tshift
)

# mean of array POArat * TempFactor for this inverter
# could make more sense to use weighted mean with weights set
# by array power percentage
# another alternative, calculate average POArat and TempFactor separately
poa_rat = [pa / pr for pa, pr in zip(poa_actual, poa_ref)]
poa_rat = [_zero_div(pa, pr) for pa, pr in zip(poa_actual, poa_ref)]
tempfactor = list(map(_temp_factor, gammas, t_ref, t_actual))
poa_rat_x_temp_factor = adjust( # modelchain outputs are all shifted
sum([p * t for p, t in zip(poa_rat, tempfactor)]) / num_arrays
Expand Down
60 changes: 58 additions & 2 deletions api/solarperformanceinsight_api/tests/test_compute.py
Original file line number Diff line number Diff line change
Expand Up @@ -895,9 +895,25 @@ def actual_params(irr_type, temp_type, weather_gran, perf_gran):


@pytest.fixture()
def pvsyst_system():
def sandia_inverter():
return dict(
Paco=5000,
Pdco=5447.35,
Vdco=48,
Pso=18.11,
C0=-1.1e-5,
C1=3.26e-4,
C2=-5.6e-3,
C3=-1.2e-3,
Pnt=1.5,
)


@pytest.fixture()
def pvsyst_system(sandia_inverter):
sysdict = deepcopy(models.SYSTEM_EXAMPLE)
inv = sysdict["inverters"][0]
inv["inverter_parameters"] = sandia_inverter
inv1 = deepcopy(inv)
inv1["name"] = "inverter 2"
inv1["arrays"] = [inv1["arrays"][0], inv1["arrays"][0]]
Expand All @@ -906,7 +922,7 @@ def pvsyst_system():


@pytest.fixture()
def cec_system():
def cec_system(sandia_inverter):
sysdict = deepcopy(models.SYSTEM_EXAMPLE)
modparams = models.CECModuleParameters(
alpha_sc=0.00208,
Expand All @@ -920,8 +936,10 @@ def cec_system():
Adjust=13.095,
)
inv = sysdict["inverters"][0]
inv["inverter_parameters"] = sandia_inverter
arr = inv["arrays"][0]
arr["module_parameters"] = modparams
arr["strings"] = 1
inv["arrays"] = [arr]
inv1 = deepcopy(inv)
inv1["name"] = "inverter 2"
Expand Down Expand Up @@ -1173,3 +1191,41 @@ def test_compare_predicted_and_actual_cec(
)
assert "difference" in ser
assert "ratio" in ser


def test_compare_predicted_and_actual_cec_module_temp_as_expected(
mockup_predicted_actual,
auth0_id,
nocommit_transaction,
cec_system,
):
actual_params = dict(
irradiance_type="poa",
temperature_type="cell",
weather_granularity="system",
performance_granularity="inverter",
)
pred_params = dict(
irradiance_type="standard",
temperature_type="module",
weather_granularity="system",
data_available="weather only",
)
si = storage.StorageInterface(user=auth0_id)
job, save = mockup_predicted_actual(cec_system, pred_params, actual_params)
compute.compare_predicted_and_actual(job, si)
assert save.call_count == 1
reslist = save.call_args[0][1]

perf = reslist[2]
assert perf.type == "weather adjusted performance"
assert perf.schema_path == "/inverters/0"
iob = BytesIO(perf.data)
iob.seek(0)
# 2021-02-01 11:00:00-07:00 1069.703613 if using cell temp from 20C
assert (
pd.read_feather(iob)
.set_index("time")
.loc["2021-02-01 11:00:00-07:00", "performance"]
> 1070
)

0 comments on commit 6d7a3c7

Please sign in to comment.