204 lines
6.7 KiB
Rust
204 lines
6.7 KiB
Rust
//! Kjører en fullstendig energiberegning: fra bygningsbeskrivelse til energikarakter.
|
|||
|
|
|
||
|
|
use crate::data::Datakilde;
|
||
|
|
use crate::klima::{korreksjon, tmy, Vaerdata, REFERANSEKLIMA};
|
||
|
|
use crate::merking::{karakter, Energikarakter};
|
||
|
|
use crate::modell::lost::{Forutsetning, Lost};
|
||
|
|
use crate::modell::Bygning;
|
||
|
|
use crate::motor::{iso52016::Systemtilskudd, simuler, Timeserie, Varmetapsbudsjett};
|
||
|
|
use crate::systemer::{self, Effektbehov, Energibudsjett, Levert, Systemoppsett};
|
||
|
|
use crate::Result;
|
||
|
|
use serde::Serialize;
|
||
|
|
|
||
|
|
/// Alt som kommer ut av én beregning.
|
||
|
|
pub struct Resultat {
|
||
|
|
pub bygning: Bygning,
|
||
|
|
pub lost: Lost,
|
||
|
|
pub vaerdata: Vaerdata,
|
||
|
|
pub klimanavn: String,
|
||
|
|
pub varmetap: Varmetapsbudsjett,
|
||
|
|
pub timeserie: Timeserie,
|
||
|
|
pub systemer: Systemoppsett,
|
||
|
|
pub budsjett: Energibudsjett,
|
||
|
|
pub levert: Levert,
|
||
|
|
pub karakter: Energikarakter,
|
||
|
|
pub effektbehov: Effektbehov,
|
||
|
|
pub solceller: Option<crate::systemer::solcelle::Produksjon>,
|
||
|
|
pub merknader: Vec<String>,
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Kompakt, serialiserbart sammendrag for `resultat.json`.
|
||
|
|
#[derive(Serialize)]
|
||
|
|
pub struct Sammendrag<'a> {
|
||
|
|
pub navn: &'a str,
|
||
|
|
pub kategori: &'a str,
|
||
|
|
pub byggeaar: i32,
|
||
|
|
pub oppvarmet_bra: f64,
|
||
|
|
pub klimasted: &'a str,
|
||
|
|
pub referanseklima: &'a str,
|
||
|
|
pub varmetapsbudsjett: &'a Varmetapsbudsjett,
|
||
|
|
pub energibudsjett: &'a Energibudsjett,
|
||
|
|
pub netto_spesifikk: f64,
|
||
|
|
pub levert: &'a Levert,
|
||
|
|
pub energikarakter: &'a Energikarakter,
|
||
|
|
pub effektbehov: &'a Effektbehov,
|
||
|
|
pub forutsetninger: &'a [Forutsetning],
|
||
|
|
pub merknader: &'a [String],
|
||
|
|
pub maanedsverdier: Maanedsverdier,
|
||
|
|
}
|
||
|
|
|
||
|
|
#[derive(Serialize)]
|
||
|
|
pub struct Maanedsverdier {
|
||
|
|
pub maaned: [&'static str; 12],
|
||
|
|
pub romoppvarming: [f64; 12],
|
||
|
|
pub ventilasjonsvarme: [f64; 12],
|
||
|
|
pub varmtvann: [f64; 12],
|
||
|
|
pub vifter_pumper: [f64; 12],
|
||
|
|
pub belysning: [f64; 12],
|
||
|
|
pub utstyr: [f64; 12],
|
||
|
|
pub kjoling: [f64; 12],
|
||
|
|
pub utetemperatur: [f64; 12],
|
||
|
|
}
|
||
|
|
|
||
|
|
impl Resultat {
|
||
|
|
pub fn sammendrag(&self) -> Sammendrag<'_> {
|
||
|
|
let m = |s: &[f64]| Timeserie::maaned_kwh(s);
|
||
|
|
let mut vifter_pumper = m(&self.timeserie.vifter);
|
||
|
|
let pumper = m(&self.timeserie.pumper);
|
||
|
|
let mut kjoling = m(&self.timeserie.romkjoling);
|
||
|
|
let ventkjol = m(&self.timeserie.ventilasjonskjoling);
|
||
|
|
for i in 0..12 {
|
||
|
|
vifter_pumper[i] += pumper[i];
|
||
|
|
kjoling[i] += ventkjol[i];
|
||
|
|
}
|
||
|
|
Sammendrag {
|
||
|
|
navn: &self.lost.navn,
|
||
|
|
kategori: self.lost.kategori.nokkel(),
|
||
|
|
byggeaar: self.lost.byggeaar,
|
||
|
|
oppvarmet_bra: self.lost.bra,
|
||
|
|
klimasted: &self.klimanavn,
|
||
|
|
referanseklima: REFERANSEKLIMA,
|
||
|
|
varmetapsbudsjett: &self.varmetap,
|
||
|
|
energibudsjett: &self.budsjett,
|
||
|
|
netto_spesifikk: self.budsjett.netto_spesifikk(self.lost.bra),
|
||
|
|
levert: &self.levert,
|
||
|
|
energikarakter: &self.karakter,
|
||
|
|
effektbehov: &self.effektbehov,
|
||
|
|
forutsetninger: &self.lost.forutsetninger,
|
||
|
|
merknader: &self.merknader,
|
||
|
|
maanedsverdier: Maanedsverdier {
|
||
|
|
maaned: crate::MAANEDER,
|
||
|
|
romoppvarming: m(&self.timeserie.romoppvarming),
|
||
|
|
ventilasjonsvarme: m(&self.timeserie.ventilasjonsvarme),
|
||
|
|
varmtvann: m(&self.timeserie.varmtvann),
|
||
|
|
vifter_pumper,
|
||
|
|
belysning: m(&self.timeserie.belysning),
|
||
|
|
utstyr: m(&self.timeserie.utstyr),
|
||
|
|
kjoling,
|
||
|
|
utetemperatur: self.vaerdata.maanedsmiddeltemperatur(),
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// Henter værdata for bygningen: egen EPW-fil, oppgitt kommune, eller referanseklimaet.
|
||
|
|
pub fn hent_klima(b: &Bygning) -> Result<(Vaerdata, String, bool)> {
|
||
|
|
if let Some(sti) = &b.klima.epw {
|
||
|
|
let v = Vaerdata::fra_fil(sti)?;
|
||
|
|
let navn = v.sted.clone();
|
||
|
|
let er_referanse = crate::data::normaliser_stedsnavn(&navn)
|
||
|
|
== crate::data::normaliser_stedsnavn(REFERANSEKLIMA);
|
||
|
|
return Ok((v, navn, er_referanse));
|
||
|
|
}
|
||
|
|
let sted = b
|
||
|
|
.klima
|
||
|
|
.kommune
|
||
|
|
.clone()
|
||
|
|
.unwrap_or_else(|| REFERANSEKLIMA.to_string());
|
||
|
|
let er_referanse = crate::data::normaliser_stedsnavn(&sted)
|
||
|
|
== crate::data::normaliser_stedsnavn(REFERANSEKLIMA);
|
||
|
|
let v = tmy::for_kommune(&sted)?;
|
||
|
|
Ok((v, sted, er_referanse))
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn kjor(b: &Bygning, kilde: &Datakilde) -> Result<Resultat> {
|
||
|
|
let lost = Lost::fra(b, kilde)?;
|
||
|
|
let (vaerdata, klimanavn, er_referanse) = hent_klima(b)?;
|
||
|
|
kjor_med_klima(b, kilde, lost, vaerdata, klimanavn, er_referanse)
|
||
|
|
}
|
||
|
|
|
||
|
|
pub fn kjor_med_klima(
|
||
|
|
b: &Bygning,
|
||
|
|
kilde: &Datakilde,
|
||
|
|
lost: Lost,
|
||
|
|
vaerdata: Vaerdata,
|
||
|
|
klimanavn: String,
|
||
|
|
er_referanse: bool,
|
||
|
|
) -> Result<Resultat> {
|
||
|
|
let varmetap = Varmetapsbudsjett::beregn(&lost);
|
||
|
|
let systemer_oppsett = systemer::sett_opp_systemer(b, &lost, kilde)?;
|
||
|
|
let mut merknader = systemer_oppsett.merknader.clone();
|
||
|
|
|
||
|
|
let tilskudd = Systemtilskudd {
|
||
|
|
tappevann: systemer::tappevannstilskudd(&lost, &systemer_oppsett),
|
||
|
|
};
|
||
|
|
let timeserie = simuler(&lost, &vaerdata, tilskudd)?;
|
||
|
|
let budsjett = systemer::energibudsjett(×erie, &systemer_oppsett);
|
||
|
|
|
||
|
|
let solceller = b.solcelle.as_ref().map(|s| {
|
||
|
|
systemer::solcelle::beregn(s, &vaerdata, ×erie, &systemer_oppsett, lost.albedo)
|
||
|
|
});
|
||
|
|
let (egenbruk, eksportert) = solceller
|
||
|
|
.as_ref()
|
||
|
|
.map(|p| (p.egenbruk_kwh, p.eksportert_kwh))
|
||
|
|
.unwrap_or((0.0, 0.0));
|
||
|
|
|
||
|
|
let korrigering = if er_referanse {
|
||
|
|
None
|
||
|
|
} else {
|
||
|
|
let tabell = kilde.klimakorreksjon()?;
|
||
|
|
let klimaavhengig = systemer::klimaavhengig_spesifikk(&budsjett, lost.bra);
|
||
|
|
let k = korreksjon::korriger(&tabell, &klimanavn, lost.kategori, klimaavhengig);
|
||
|
|
if k.is_none() {
|
||
|
|
merknader.push(format!(
|
||
|
|
"Fant ingen klimakorrigeringsfaktor for «{klimanavn}». Energiytelsen er oppgitt i lokalt \
|
||
|
|
klima og er ikke sammenlignbar med energimerkeskalaen."
|
||
|
|
));
|
||
|
|
}
|
||
|
|
k
|
||
|
|
};
|
||
|
|
|
||
|
|
let vekting = kilde.vekting()?;
|
||
|
|
let levert = systemer::levert(
|
||
|
|
&budsjett,
|
||
|
|
&vekting,
|
||
|
|
lost.bra,
|
||
|
|
korrigering,
|
||
|
|
egenbruk,
|
||
|
|
eksportert,
|
||
|
|
);
|
||
|
|
let skala = kilde.skala()?;
|
||
|
|
let karakter = karakter(
|
||
|
|
skala.for_kategori(lost.kategori)?,
|
||
|
|
levert.spesifikk_vektet,
|
||
|
|
lost.skala_areal,
|
||
|
|
);
|
||
|
|
let effektbehov = systemer::effektbehov(×erie, &systemer_oppsett);
|
||
|
|
|
||
|
|
Ok(Resultat {
|
||
|
|
bygning: b.clone(),
|
||
|
|
lost,
|
||
|
|
vaerdata,
|
||
|
|
klimanavn,
|
||
|
|
varmetap,
|
||
|
|
timeserie,
|
||
|
|
systemer: systemer_oppsett,
|
||
|
|
budsjett,
|
||
|
|
levert,
|
||
|
|
karakter,
|
||
|
|
effektbehov,
|
||
|
|
solceller,
|
||
|
|
merknader,
|
||
|
|
})
|
||
|
|
}
|