Legg til barnehage, kontor-, skole-, idretts- og kulturbygg

Driftstidene har nå dager per uke og uker per år, og lastene gjelder bare på driftsdager.
Normerte verdier for de nye kategoriene er hentet fra publiserte Simien-utskrifter og
DiBK-utredninger og kontrollert mot energibudsjettene i de samme kildene. Boligblokk har
fått egne verdier i stedet for en kopi av småhus.

Balanserte anlegg kan ha kjølebatteri, og varmegjenvinneren reguleres ned når den ellers
ville varmet tilluften over settpunktet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GeH3y8fwTaTudaD88P57o
This commit is contained in:
bl
2026-09-15 20:05:20 +02:00
co-authored by Claude Opus 5
parent cb64c91b19
commit d02a3d9666
16 changed files with 601 additions and 39 deletions
+143
View File
@@ -0,0 +1,143 @@
//! Kontroll av de normerte inndataene for yrkesbyggkategoriene: driftsdager, faste energiposter
//! og kjølebatteri.
use enok::data::Datakilde;
use enok::kjor;
use enok::modell::{Bygning, Kategori};
fn prøvebygg(kategori: &str, kjolebatteri: bool) -> Bygning {
let s = format!(
r#"
[bygning]
navn = "Prøvebygg"
kategori = "{kategori}"
byggeaar = 2020
oppvarmet_bra = 1200.0
oppvarmet_volum = 3840.0
[klima]
kommune = "Oslo"
[[flate]]
navn = "Vegger"
type = "vegg"
areal = 560.0
u_verdi = 0.18
[[flate]]
navn = "Tak"
type = "tak"
areal = 600.0
u_verdi = 0.13
[[flate]]
navn = "Gulv"
type = "gulv"
areal = 600.0
u_verdi = 0.10
[[vindu]]
navn = "Sør"
areal = 150.0
orientering = 180
u_verdi = 0.8
g_verdi = 0.5
[infiltrasjon]
n50 = 0.6
[ventilasjon]
type = "balansert"
gjenvinning = 0.85
kjolebatteri = {kjolebatteri}
[[oppvarming.kilde]]
type = "direkte_el"
andel_rom = 1.0
andel_tappevann = 1.0
"#
);
toml::from_str(&s).unwrap()
}
fn post(r: &kjor::Resultat, nr: &str) -> f64 {
let p = r.budsjett.poster.iter().find(|p| p.nr == nr).unwrap();
p.netto / r.lost.bra
}
fn naer(faktisk: f64, forventet: f64, hva: &str) {
assert!(
(faktisk - forventet).abs() <= 0.1,
"{hva}: beregnet {faktisk:.2}, forventet {forventet:.2}"
);
}
#[test]
fn driftsdager_per_aar() {
let kilde = Datakilde::default();
for (kategori, dager) in [
(Kategori::Smaahus, 365),
(Kategori::Boligblokk, 365),
(Kategori::Barnehage, 261),
(Kategori::Kontorbygg, 261),
(Kategori::Kulturbygg, 261),
(Kategori::Skolebygg, 220),
(Kategori::Idrettsbygg, 220),
] {
let n = kilde.normerte(kategori).unwrap();
assert_eq!(
n.driftstid.driftsdager_per_aar(),
dager,
"{}",
kategori.nokkel()
);
}
}
/// Fellesferien og helgene er uten drift i skolebygg.
#[test]
fn skolebygg_stengt_i_helg_og_ferie() {
let n = Datakilde::default().normerte(Kategori::Skolebygg).unwrap();
let d = &n.driftstid;
assert!(d.driftsdag(0), "1. januar er mandag i uke 1");
assert!(!d.driftsdag(5), "lørdag");
assert!(!d.driftsdag(6), "søndag");
assert!(!d.driftsdag(7 * 28), "mandag i uke 29");
assert!(d.driftsdag(7 * 34), "mandag i uke 35");
}
/// Belysning, utstyr og varmtvann skal gi energibehovene som følger av tabellverdiene.
#[test]
fn faste_poster_som_tabellverdiene() {
let kilde = Datakilde::default();
for (kategori, belysning, utstyr, varmtvann) in [
("barnehage", 20.9, 5.2, 10.0),
("kontorbygg", 25.1, 34.5, 5.0),
("skolebygg", 22.0, 13.2, 10.0),
("idrettsbygg", 21.1, 2.6, 50.2),
("kulturbygg", 23.0, 2.9, 10.0),
] {
let r = kjor::kjor(&prøvebygg(kategori, false), &kilde).unwrap();
naer(post(&r, "5"), belysning, &format!("{kategori} belysning"));
naer(post(&r, "6"), utstyr, &format!("{kategori} utstyr"));
naer(post(&r, "2"), varmtvann, &format!("{kategori} varmtvann"));
}
}
/// Kjølebatteriet gir ventilasjonskjøling; uten det er posten null.
#[test]
fn kjolebatteri_gir_ventilasjonskjoling() {
let kilde = Datakilde::default();
let uten = kjor::kjor(&prøvebygg("kontorbygg", false), &kilde).unwrap();
let med = kjor::kjor(&prøvebygg("kontorbygg", true), &kilde).unwrap();
assert_eq!(post(&uten, "3b"), 0.0);
assert!(
post(&med, "3b") > 0.5,
"ventilasjonskjøling {:.2}",
post(&med, "3b")
);
// Kjøling skjer bare i driftstiden på driftsdager.
let ts = &med.timeserie;
let lørdag_middag = 5 * 24 + 12 + 24 * 7 * 26;
assert_eq!(ts.ventilasjonskjoling[lørdag_middag], 0.0);
}
+2 -2
View File
@@ -86,13 +86,13 @@ fn regresjonsvakt_for_romoppvarming() {
let r = kjor_referansebygg();
naer(
post(&r, "1a"),
27.2,
27.1,
1.5,
"romoppvarming (regresjon, publisert verdi 46,2)",
);
naer(
r.budsjett.netto_spesifikk(r.lost.bra),
86.7,
86.6,
2.0,
"netto energibehov (regresjon, publisert verdi 106,4)",
);