Files
enok/src/modell/mod.rs
T
blandClaude Opus 5 c89561b0f5
Release enok / bygg (release) Successful in 1m12s
test / test (push) Successful in 1m16s
Gi rapporten plass til kildene, og la den følge egne dokumenter
Kolonnen «Kilde» i forutsetningstabellen fikk for liten plass, fordi de to første kolonnene
tok det de ville. Kolonnene har nå faste bredder, og tabellen leses på én linje per rad.

En ny [rapport]-tabell i bygningsbeskrivelsen setter logo, aksentfarge, avsenderlinje og
skrift for overskrifter, slik at energirapporten kan se ut som firmaets øvrige rapporter.
Logoen kopieres til utdatakatalogen; mangler filen, lages rapporten uten den.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GeH3y8fwTaTudaD88P57o
2026-09-20 22:02:36 +02:00

686 lines
24 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 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>,
#[serde(default)]
pub rapport: Rapport,
}
/// Utseendet på rapporten, slik at den kan følge firmaets øvrige dokumenter.
#[derive(Deserialize, Serialize, Clone, Debug, Default)]
#[serde(deny_unknown_fields)]
pub struct Rapport {
/// Logo på forsiden. Filen kopieres til utdatakatalogen ved siden av rapporten.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub logo: Option<PathBuf>,
/// Aksentfarge, for eksempel «#880000». Utelatt: enoks egen.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub farge: Option<String>,
/// Avsenderlinje nederst på hver side, for eksempel firma og organisasjonsnummer.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub avsender: Option<String>,
/// Skrift for overskrifter. Utelatt: enoks egen.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub skrift_overskrift: Option<String>,
}
#[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 (01). 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,
/// U-verdi inkl. karm, W/(m²K). Utelatt: typisk for byggeåret.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub u_verdi: Option<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 (01). 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>,
/// Har anlegget kjølebatteri? Tilluften holdes da på `tilluft_kjoling` i driftstiden.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub kjolebatteri: Option<bool>,
/// Tilluftstemperatur med kjølebatteri, °C. Utelatt: normert.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tilluft_kjoling: Option<f64>,
}
#[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 luftluft",
VarmekildeType::LuftVannVp => "Varmepumpe luftvann",
VarmekildeType::VaeskeVannVp => "Varmepumpe væskevann (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 (01).
#[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;