En ny eksport av Nordhusstykket 5 viste hva mer modellen kan bære, og avdekket feil. Posisjon og klimasted - IfcMapConversion med IfcProjectedCRS gjøres om til breddegrad og lengdegrad. EUREF89 og WGS 84 UTM, NN2000-varianter og Web Mercator forstås. Omregningen er kontrollert mot PROJ. - Vectorworks' standardplassering i Washington, som står når ingenting er satt, kjennes igjen og brukes ikke. - Ny `posisjon` under [klima]. Uten kommune velger beregningen nærmeste av de 358 klimastedene i TMY-arkivet, og sier i rapporten hvor langt unna det ligger. Opplysninger fra modellen - Adressen hentes fra IfcBuilding eller IfcSite. Før ble den første postadressen i filen brukt, og det var firmaets adresse i forfatteropplysningene. - Energirådgiver fra person og organisasjon i forfatteropplysningene. - Byggets navn fra prosjektet når bygningen heter «Default Building». - Referansehøyde og terrenghøyde på bygningen gir hvor mye av grunnmuren som står over bakken. - IsLandmarked gir en merknad om at vernede bygninger er unntatt energiattestplikten. En eksport uten bygningsdeler stopper nå med en feilmelding som peker på lagtilknytningen i eksportdialogen, i stedet for å skrive en tom bygning. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015GeH3y8fwTaTudaD88P57o
658 lines
23 KiB
Rust
658 lines
23 KiB
Rust
//! Inndatamodell for en bygning (`bygning.toml`). Alt en energirådgiver kan variere ligger her;
|
||
//! det som utelates hentes fra normerte verdier for kategorien og merkes i rapporten.
|
||
|
||
use serde::{Deserialize, Serialize};
|
||
use std::path::PathBuf;
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum Kategori {
|
||
Smaahus,
|
||
Boligblokk,
|
||
Barnehage,
|
||
Kontorbygg,
|
||
Skolebygg,
|
||
Universitet,
|
||
Sykehus,
|
||
Sykehjem,
|
||
Hotell,
|
||
Idrettsbygg,
|
||
Forretningsbygg,
|
||
Kulturbygg,
|
||
Industribygg,
|
||
}
|
||
|
||
impl Kategori {
|
||
pub fn nokkel(&self) -> &'static str {
|
||
match self {
|
||
Kategori::Smaahus => "smaahus",
|
||
Kategori::Boligblokk => "boligblokk",
|
||
Kategori::Barnehage => "barnehage",
|
||
Kategori::Kontorbygg => "kontorbygg",
|
||
Kategori::Skolebygg => "skolebygg",
|
||
Kategori::Universitet => "universitet",
|
||
Kategori::Sykehus => "sykehus",
|
||
Kategori::Sykehjem => "sykehjem",
|
||
Kategori::Hotell => "hotell",
|
||
Kategori::Idrettsbygg => "idrettsbygg",
|
||
Kategori::Forretningsbygg => "forretningsbygg",
|
||
Kategori::Kulturbygg => "kulturbygg",
|
||
Kategori::Industribygg => "industribygg",
|
||
}
|
||
}
|
||
pub fn er_bolig(&self) -> bool {
|
||
matches!(self, Kategori::Smaahus | Kategori::Boligblokk)
|
||
}
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
#[serde(deny_unknown_fields)]
|
||
pub struct Bygning {
|
||
pub bygning: BygningInfo,
|
||
#[serde(default)]
|
||
pub klima: Klima,
|
||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||
pub flate: Vec<Flate>,
|
||
/// Uoppvarmede soner, typisk kjeller eller loft, med egen temperaturberegning.
|
||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||
pub sone: Vec<Sone>,
|
||
#[serde(default)]
|
||
pub grunn: Grunn,
|
||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||
pub vindu: Vec<Vindu>,
|
||
#[serde(default)]
|
||
pub kuldebroer: Kuldebroer,
|
||
#[serde(default)]
|
||
pub infiltrasjon: Infiltrasjon,
|
||
#[serde(default)]
|
||
pub ventilasjon: Ventilasjon,
|
||
#[serde(default)]
|
||
pub tappevann: Tappevann,
|
||
#[serde(default)]
|
||
pub oppvarming: Oppvarming,
|
||
#[serde(default)]
|
||
pub distribusjon: Distribusjon,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub solcelle: Option<Solcelle>,
|
||
#[serde(default)]
|
||
pub kjoling: Kjoling,
|
||
#[serde(default)]
|
||
pub lufting: Lufting,
|
||
#[serde(default)]
|
||
pub drift: Drift,
|
||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||
pub scenario: Vec<Scenario>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct BygningInfo {
|
||
pub navn: String,
|
||
pub kategori: Kategori,
|
||
pub byggeaar: i32,
|
||
/// Oppvarmet del av bruksareal, m².
|
||
pub oppvarmet_bra: f64,
|
||
/// Oppvarmet luftvolum, m³. Utelatt: 2,4 m × BRA.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub oppvarmet_volum: Option<f64>,
|
||
#[serde(default = "en")]
|
||
pub antall_boenheter: u32,
|
||
/// Samlet oppvarmet BRA for hele bygningen når én boenhet i flerbolighus merkes.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub bygningens_oppvarmede_bra: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub adresse: Option<String>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub gnr_bnr: Option<String>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub beskrivelse: Option<String>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub energiraadgiver: Option<String>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub oppdragsgiver: Option<String>,
|
||
}
|
||
|
||
fn en() -> u32 {
|
||
1
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Klima {
|
||
/// Byggets posisjon som [breddegrad, lengdegrad]. Er kommune ikke oppgitt, velges
|
||
/// klimastedet nærmest denne posisjonen.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub posisjon: Option<[f64; 2]>,
|
||
/// Kommune for lokalt klima (TMY-fil fra Zenodo 14779899). Utelatt: bare Oslo.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub kommune: Option<String>,
|
||
/// Egen EPW-fil for lokalt klima (overstyrer kommune).
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub epw: Option<PathBuf>,
|
||
/// Referanseklima for energimerket. Standard «Oslo».
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub referanse: Option<String>,
|
||
/// Bakkerefleksjon (albedo) for solstråling. Standard 0,2.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub albedo: Option<f64>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum FlateType {
|
||
Vegg,
|
||
Tak,
|
||
Gulv,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum Mot {
|
||
#[default]
|
||
Ute,
|
||
Grunn,
|
||
Uoppvarmet,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum Masseklasse {
|
||
SvaertLett,
|
||
Lett,
|
||
Middels,
|
||
Tung,
|
||
SvaertTung,
|
||
}
|
||
|
||
impl Masseklasse {
|
||
/// Arealspesifikk varmekapasitet κ_m, J/(m²K) (ISO 52016-1 Tabell B.14).
|
||
pub fn kappa(&self) -> f64 {
|
||
match self {
|
||
Masseklasse::SvaertLett => 50_000.0,
|
||
Masseklasse::Lett => 75_000.0,
|
||
Masseklasse::Middels => 110_000.0,
|
||
Masseklasse::Tung => 175_000.0,
|
||
Masseklasse::SvaertTung => 250_000.0,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Hvor massen sitter i konstruksjonen (ISO 52016-1 klasse I/E/IE/D/M).
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum Masseplassering {
|
||
Innvendig,
|
||
Utvendig,
|
||
Begge,
|
||
#[default]
|
||
Fordelt,
|
||
Midt,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Lag {
|
||
pub materiale: String,
|
||
pub tykkelse: f64,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Flate {
|
||
pub navn: String,
|
||
#[serde(rename = "type")]
|
||
pub typ: FlateType,
|
||
pub areal: f64,
|
||
/// Himmelretning flatens utside vender mot, grader fra nord med klokka (0 N, 90 Ø, 180 S, 270 V).
|
||
#[serde(default)]
|
||
pub orientering: f64,
|
||
/// Helning fra horisontalplanet: 90 = vertikal vegg, 0 = flatt tak. Utelatt: 90 for vegg, 0 for tak/gulv.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub helning: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub u_verdi: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub lag: Option<Vec<Lag>>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub masseklasse: Option<Masseklasse>,
|
||
#[serde(default)]
|
||
pub masseplassering: Masseplassering,
|
||
#[serde(default)]
|
||
pub mot: Mot,
|
||
/// Temperaturfaktor b for uoppvarmet rom. Utelatt: 0,5 (loft/kjeller), jf. NS-EN ISO 13789.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub b_faktor: Option<f64>,
|
||
/// Solabsorptans for utvendig overflate. Utelatt: 0,6.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub absorptans: Option<f64>,
|
||
/// Gulv mot grunn: eksponert omkrets, m. Brukes i den karakteristiske dimensjonen B′.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub omkrets: Option<f64>,
|
||
/// Dybde under terreng, m. For gulv: gulvets dybde. For kjellervegg: veggens nedgravde høyde.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub dybde: Option<f64>,
|
||
/// Kjellervegg: høyden som står over terreng, m. Den delen regnes som vanlig yttervegg,
|
||
/// og arealet deles mellom over og under terreng i forhold til høydene.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub over_terreng: Option<f64>,
|
||
/// Navnet på den uoppvarmede sonen flaten vender mot, når `mot = "uoppvarmet"`.
|
||
/// Uten dette brukes temperaturfaktoren `b_faktor` i stedet.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub sone: Option<String>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub kommentar: Option<String>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum SolskjermingType {
|
||
#[default]
|
||
Ingen,
|
||
Manuell,
|
||
Automatisk,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Solskjerming {
|
||
#[serde(rename = "type")]
|
||
pub typ: SolskjermingType,
|
||
/// Gjennomslipp når skjermingen er i bruk (0–1). Utelatt: 0,8 manuell, 0,4 automatisk.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub faktor: Option<f64>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Vindu {
|
||
pub navn: String,
|
||
/// Areal inkl. karm, m².
|
||
pub areal: f64,
|
||
#[serde(default = "en_f64")]
|
||
pub antall: f64,
|
||
#[serde(default)]
|
||
pub orientering: f64,
|
||
#[serde(default = "nitti")]
|
||
pub helning: f64,
|
||
pub u_verdi: f64,
|
||
/// Solfaktor for glasset (g-verdi). Utelatt: 0,75 for 2-lags, 0,5 for 3-lags energiglass.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub g_verdi: Option<f64>,
|
||
/// Karm- og rammeandel av arealet. Utelatt: 0,2.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub karmandel: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub solskjerming: Option<Solskjerming>,
|
||
/// Horisontavskjerming i grader (terreng, nabobygg). Utelatt: 0.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub horisont: Option<f64>,
|
||
/// Er dette en dør (regnes uten solinnstråling)?
|
||
#[serde(default)]
|
||
pub dor: bool,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub kommentar: Option<String>,
|
||
}
|
||
|
||
fn en_f64() -> f64 {
|
||
1.0
|
||
}
|
||
fn nitti() -> f64 {
|
||
90.0
|
||
}
|
||
|
||
/// Grunnforhold for beregning etter NS-EN ISO 13370.
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Grunn {
|
||
/// Varmeledningsevne for jorda, W/(m·K). Utelatt: 2,0 (leire eller silt).
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub ledningsevne: Option<f64>,
|
||
}
|
||
|
||
/// En uoppvarmet sone, typisk kjeller, loft eller garasje.
|
||
///
|
||
/// Sonen har ingen egen oppvarming, men får varme fra den oppvarmede delen gjennom
|
||
/// etasjeskilleren og fra varmerør og bereder som står der. Temperaturen regnes ut time for
|
||
/// time av varmebalansen etter NS-EN ISO 13789, slik at et varmt rørnett i kjelleren både
|
||
/// teller som tap fra varmeanlegget og som varme som holder etasjeskilleren varm.
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Sone {
|
||
pub navn: String,
|
||
/// Luftvolum, m³. Brukes til ventilasjonstapet fra sonen.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub volum: Option<f64>,
|
||
/// Luftvekslinger per time mot det fri. Utelatt: 0,3 for en kjeller.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub luftveksling: Option<f64>,
|
||
/// Sonens egne flater mot det fri og mot grunnen.
|
||
#[serde(default, rename = "flate", skip_serializing_if = "Vec::is_empty")]
|
||
pub flater: Vec<Flate>,
|
||
/// Andel av varmeanleggets distribusjonstap som avgis i denne sonen. Utelatt: 1,0 når
|
||
/// bygningen har vannbåren varme og sonen er den eneste uoppvarmede.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub andel_distribusjonstap: Option<f64>,
|
||
/// Andel av tappevannsanleggets tap som avgis her.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub andel_tappevannstap: Option<f64>,
|
||
/// Fast varmetilskudd i sonen, W. For eksempel kappetap fra en kjel.
|
||
#[serde(default)]
|
||
pub fast_effekt: f64,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub kommentar: Option<String>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Kuldebroer {
|
||
/// Normalisert kuldebroverdi, W/(m²K) av oppvarmet BRA. Utelatt: verdi etter byggeår.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub normalisert: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||
pub liste: Vec<Kuldebro>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Kuldebro {
|
||
pub navn: String,
|
||
pub psi: f64,
|
||
pub lengde: f64,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum Skjerming {
|
||
Skjermet,
|
||
#[default]
|
||
Moderat,
|
||
Utsatt,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Infiltrasjon {
|
||
/// Lekkasjetall ved 50 Pa, 1/h. Utelatt: verdi etter byggeår.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub n50: Option<f64>,
|
||
#[serde(default)]
|
||
pub skjerming: Skjerming,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub maalt_dato: Option<String>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum VentilasjonType {
|
||
#[default]
|
||
Naturlig,
|
||
Avtrekk,
|
||
Balansert,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Ventilasjon {
|
||
#[serde(rename = "type", default)]
|
||
pub typ: VentilasjonType,
|
||
/// Gjennomsnittlig luftmengde i driftstiden, m³/(h·m²). Utelatt: normert.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub luftmengde: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub luftmengde_natt: Option<f64>,
|
||
/// Temperaturvirkningsgrad varmegjenvinner (0–1). Bare balansert. Utelatt: normert.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub gjenvinning: Option<f64>,
|
||
/// Spesifikk vifteeffekt, kW/(m³/s). Utelatt: normert (balansert) / 0,6 (avtrekk).
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub sfp: Option<f64>,
|
||
/// Har anlegget varmebatteri som ettervarmer tilluften?
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub varmebatteri: Option<bool>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum TappevannSystem {
|
||
#[default]
|
||
Aapent,
|
||
Sirkulasjon,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Tappevann {
|
||
#[serde(default)]
|
||
pub system: TappevannSystem,
|
||
/// Netto energibehov, kWh/(m²·år). Utelatt: normert.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub energibehov: Option<f64>,
|
||
/// Tap i bereder og rør som andel av netto behov. Utelatt: 0,25 åpent, 0,45 sirkulasjon.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub tap_andel: Option<f64>,
|
||
/// Andel av tapet som avgis i oppvarmet sone (uregulerbart varmetilskudd). Utelatt: 0,8 / 0,5.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub tap_i_oppvarmet_sone: Option<f64>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum VarmekildeType {
|
||
DirekteEl,
|
||
ElKjel,
|
||
LuftLuftVp,
|
||
LuftVannVp,
|
||
VaeskeVannVp,
|
||
AvtrekkVp,
|
||
Vedovn,
|
||
Pellets,
|
||
Olje,
|
||
Gass,
|
||
Fjernvarme,
|
||
Solfanger,
|
||
}
|
||
|
||
impl VarmekildeType {
|
||
pub fn nokkel(&self) -> &'static str {
|
||
match self {
|
||
VarmekildeType::DirekteEl => "direkte_el",
|
||
VarmekildeType::ElKjel => "el_kjel",
|
||
VarmekildeType::LuftLuftVp => "luft_luft_vp",
|
||
VarmekildeType::LuftVannVp => "luft_vann_vp",
|
||
VarmekildeType::VaeskeVannVp => "vaeske_vann_vp",
|
||
VarmekildeType::AvtrekkVp => "avtrekk_vp",
|
||
VarmekildeType::Vedovn => "vedovn",
|
||
VarmekildeType::Pellets => "pellets",
|
||
VarmekildeType::Olje => "olje",
|
||
VarmekildeType::Gass => "gass",
|
||
VarmekildeType::Fjernvarme => "fjernvarme",
|
||
VarmekildeType::Solfanger => "solfanger",
|
||
}
|
||
}
|
||
pub fn beskrivelse(&self) -> &'static str {
|
||
match self {
|
||
VarmekildeType::DirekteEl => "Direkte elektrisk (panelovner, varmekabler)",
|
||
VarmekildeType::ElKjel => "Elektrokjel, vannbåren varme",
|
||
VarmekildeType::LuftLuftVp => "Varmepumpe luft–luft",
|
||
VarmekildeType::LuftVannVp => "Varmepumpe luft–vann",
|
||
VarmekildeType::VaeskeVannVp => "Varmepumpe væske–vann (berg/jord/sjø)",
|
||
VarmekildeType::AvtrekkVp => "Avtrekksvarmepumpe",
|
||
VarmekildeType::Vedovn => "Vedovn",
|
||
VarmekildeType::Pellets => "Pelletskamin/-kjel",
|
||
VarmekildeType::Olje => "Oljekjel",
|
||
VarmekildeType::Gass => "Gasskjel",
|
||
VarmekildeType::Fjernvarme => "Fjernvarme",
|
||
VarmekildeType::Solfanger => "Solfanger",
|
||
}
|
||
}
|
||
pub fn er_varmepumpe(&self) -> bool {
|
||
matches!(
|
||
self,
|
||
VarmekildeType::LuftLuftVp
|
||
| VarmekildeType::LuftVannVp
|
||
| VarmekildeType::VaeskeVannVp
|
||
| VarmekildeType::AvtrekkVp
|
||
)
|
||
}
|
||
/// Kan kilden levere til vannbåren distribusjon (ventilasjonsvarme, tappevann)?
|
||
pub fn vannbaaren(&self) -> bool {
|
||
!matches!(
|
||
self,
|
||
VarmekildeType::DirekteEl | VarmekildeType::LuftLuftVp | VarmekildeType::Vedovn
|
||
)
|
||
}
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Varmekilde {
|
||
#[serde(rename = "type")]
|
||
pub typ: VarmekildeType,
|
||
/// Andel av romoppvarmingsbehovet kilden dekker (0–1).
|
||
#[serde(default)]
|
||
pub andel_rom: f64,
|
||
/// Andel av ventilasjonsvarme. Utelatt: som andel_rom for vannbårne kilder, ellers 0.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub andel_ventilasjon: Option<f64>,
|
||
#[serde(default)]
|
||
pub andel_tappevann: f64,
|
||
/// Årsvarmefaktor (SPF) for varmepumper eller virkningsgrad for kjeler. Utelatt: tabellverdi.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub spf: Option<f64>,
|
||
/// Turtemperatur °C for vannbårne varmepumper (35/45/55).
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub turtemperatur: Option<f64>,
|
||
/// Vedovn: lukket ildsted med lavt partikkelutslipp (gir vektingsfaktor 0,45).
|
||
#[serde(default = "sann")]
|
||
pub lukket: bool,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub kommentar: Option<String>,
|
||
}
|
||
|
||
fn sann() -> bool {
|
||
true
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Oppvarming {
|
||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||
pub kilde: Vec<Varmekilde>,
|
||
/// Maks varmeeffekt installert, W (begrenser innetemperatur ved underdekning). Utelatt: ubegrenset.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub maks_effekt: Option<f64>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||
#[serde(rename_all = "snake_case")]
|
||
pub enum DistribusjonType {
|
||
#[default]
|
||
Punkt,
|
||
Radiator,
|
||
Gulvvarme,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Distribusjon {
|
||
#[serde(rename = "type", default)]
|
||
pub typ: DistribusjonType,
|
||
/// Distribusjonstap som andel av avgitt romvarme. Utelatt: 0 punkt, 0,03 radiator, 0,05 gulvvarme.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub tap_andel: Option<f64>,
|
||
/// Andel av tapet som går til uoppvarmet areal (rør i kjeller/loft). Utelatt: 0,2.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub roer_uoppvarmet: Option<f64>,
|
||
/// Pumpeeffekt, W/m² i driftstid. Utelatt: normert for vannbåren, 0 for punkt.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub pumpe_effekt: Option<f64>,
|
||
/// Turtemperatur °C i vannbårent anlegg (60 radiator, 35 gulvvarme). Brukes for SPF-oppslag.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub turtemperatur: Option<f64>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Solcelle {
|
||
/// Modulareal, m².
|
||
pub areal: f64,
|
||
#[serde(default = "tjue_prosent")]
|
||
pub virkningsgrad: f64,
|
||
#[serde(default = "sor")]
|
||
pub orientering: f64,
|
||
#[serde(default = "tretti")]
|
||
pub helning: f64,
|
||
/// Ytelsesfaktor (inverter, kabler, snø, smuss). Utelatt: 0,8.
|
||
#[serde(default = "aatti_prosent")]
|
||
pub ytelsesfaktor: f64,
|
||
}
|
||
|
||
fn tjue_prosent() -> f64 {
|
||
0.20
|
||
}
|
||
fn sor() -> f64 {
|
||
180.0
|
||
}
|
||
fn tretti() -> f64 {
|
||
30.0
|
||
}
|
||
fn aatti_prosent() -> f64 {
|
||
0.8
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Kjoling {
|
||
#[serde(default = "sann")]
|
||
pub ingen: bool,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub settpunkt: Option<f64>,
|
||
/// Årskuldefaktor (SEER). Utelatt: 3,0.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub spf: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub maks_effekt: Option<f64>,
|
||
}
|
||
|
||
impl Default for Kjoling {
|
||
fn default() -> Self {
|
||
Self {
|
||
ingen: true,
|
||
settpunkt: None,
|
||
spf: None,
|
||
maks_effekt: None,
|
||
}
|
||
}
|
||
}
|
||
|
||
/// Vinduslufting: økt luftmengde når rommene blir for varme.
|
||
///
|
||
/// Bygninger uten kjøleanlegg luftes gjennom vinduer når det blir for varmt. Uten denne
|
||
/// modellen vil en tett bygning med store vindusflater få urealistisk høye innetemperaturer
|
||
/// om våren og høsten, og lagret solvarme vil kunstig redusere oppvarmingsbehovet.
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Lufting {
|
||
/// Slår av vinduslufting. Standard er lufting for bygninger uten kjøleanlegg.
|
||
#[serde(default)]
|
||
pub ingen: bool,
|
||
/// Operativ temperatur der luftingen starter, °C. Utelatt: 24.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub settpunkt: Option<f64>,
|
||
/// Største luftmengde ved vinduslufting, m³/(h·m²) oppvarmet BRA. Utelatt: 8.
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub maks_luftmengde: Option<f64>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
|
||
pub struct Drift {
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub settpunkt_oppvarming: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub nattsenking: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub belysning_effekt: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub utstyr_effekt: Option<f64>,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub personer_varmetilskudd: Option<f64>,
|
||
/// Effektiv innvendig varmekapasitet for luft og inventar, J/(m²K). Utelatt: 10 000 (ISO 52016-1).
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub innvendig_varmekapasitet: Option<f64>,
|
||
}
|
||
|
||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||
pub struct Scenario {
|
||
pub navn: String,
|
||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||
pub beskrivelse: Option<String>,
|
||
/// Delvis bygningsbeskrivelse som flettes inn: tabeller flettes rekursivt, tabellarrayer
|
||
/// (flate, vindu, oppvarming.kilde …) matches på `navn`/`type`, skalarer erstattes.
|
||
/// `slett = true` fjerner et element.
|
||
pub endringer: toml::Value,
|
||
}
|
||
|
||
pub mod kontroll;
|
||
pub mod lost;
|