Geometri fra IFC, grunnmodell etter ISO 13370 og uoppvarmede soner
test / test (push) Failing after 3s
test / test (push) Failing after 3s
Importen er prøvd mot en virkelig IFC-fil fra Vectorworks Architect 2026 og avdekket tre feil og ett hull. IFC-import - Lengdeenheten hentes nå gjennom prosjektets enhetsoppsett. Filen inneholder to lengdeenheter, og oppslaget traff tilfeldig den ene. - Arealer regnes av geometrien, siden modellen ikke har mengder for vegger og dekker. Trekantene grupperes etter retning, og den største gruppen er delens hovedflate. Metoden gir riktig areal også når vinduer er skåret ut av veggen. - Materialsjikt eksporteres som hver sin geometridel. Deler som ligger i samme plan og overlapper hverandre telles én gang, ellers ble en vegg talt sju ganger. - Himmelretningen følger flatenormalen i stedet for et anslag ut fra tyngdepunktet. - Flater med samme konstruksjon og himmelretning slås sammen, og rommene listes med areal, siden IFC ikke sier hvilke som er oppvarmet. Grunnen og kjelleren - Flater mot grunnen regnes etter NS-EN ISO 13370. En kjellervegg deles i en del over terreng og en nedgravd del, etter høydene `over_terreng` og `dybde`. - Uoppvarmede soner får egen temperatur time for time etter NS-EN ISO 13789, med varmetilskudd fra distribusjonstap og beredere som står der. Uisolerte varmerør i en kjeller teller dermed både som tap og som varme som holder etasjeskilleren varm. - Varmetapsbudsjettet oppgir konstruksjonens egen U-verdi, slik NS 3031 Tabell 3 og energikravene i TEK er formulert, mens timesberegningen bruker grunnens demping. Nordhusstykket 5 er modellert av IFC-geometrien med kjelleren som egen sone. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015GeH3y8fwTaTudaD88P57o
This commit is contained in:
+42
-4
@@ -51,6 +51,7 @@ struct Del {
|
||||
kapasitet: Vec<f64>,
|
||||
glass: bool,
|
||||
mot: Mot,
|
||||
sone: Option<usize>,
|
||||
b_faktor: f64,
|
||||
absorptans: f64,
|
||||
helning: f64,
|
||||
@@ -94,6 +95,8 @@ pub struct Timeserie {
|
||||
pub sol_horisontal: Vec<f64>,
|
||||
/// Luftmengde ved vinduslufting, m³/h.
|
||||
pub vinduslufting: Vec<f64>,
|
||||
/// Temperatur i hver uoppvarmede sone, °C.
|
||||
pub sonetemperatur: Vec<Vec<f64>>,
|
||||
}
|
||||
|
||||
impl Timeserie {
|
||||
@@ -116,6 +119,7 @@ impl Timeserie {
|
||||
internlast: n(),
|
||||
sol_horisontal: n(),
|
||||
vinduslufting: n(),
|
||||
sonetemperatur: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,10 +144,15 @@ impl Timeserie {
|
||||
/// romoppvarmingsbehovet, samtidig som energien telles under tappevann. Distribusjonstap for
|
||||
/// romvarme i oppvarmet sone regnes ikke med her: den varmen ville uansett blitt avgitt i sonen,
|
||||
/// og påvirker derfor bare fordelingen mellom rør og varmegiver, ikke energibehovet.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Systemtilskudd {
|
||||
/// Konstant tilskudd fra tappevannsanlegget, W.
|
||||
/// Konstant tilskudd fra tappevannsanlegget i den oppvarmede sonen, W.
|
||||
pub tappevann: f64,
|
||||
/// Fast varmetilskudd i hver uoppvarmede sone, W.
|
||||
pub sone_fast: Vec<f64>,
|
||||
/// Varmetilskudd i hver uoppvarmede sone som andel av romoppvarmingseffekten.
|
||||
/// Dette er distribusjonstapet fra varmerør som går gjennom sonen.
|
||||
pub sone_andel_romvarme: Vec<f64>,
|
||||
}
|
||||
|
||||
pub fn simuler(l: &Lost, v: &Vaerdata, tilskudd: Systemtilskudd) -> Result<Timeserie> {
|
||||
@@ -155,6 +164,13 @@ pub fn simuler(l: &Lost, v: &Vaerdata, tilskudd: Systemtilskudd) -> Result<Times
|
||||
let bakketemp = bakketemperatur(v);
|
||||
|
||||
let mut ts = Timeserie::ny();
|
||||
ts.sonetemperatur = vec![vec![0.0; TIMER]; l.soner.len()];
|
||||
let mut t_soner: Vec<f64> = l
|
||||
.soner
|
||||
.iter()
|
||||
.map(|_| l.settpunkt_oppvarming - 5.0)
|
||||
.collect();
|
||||
let mut romvarme_forrige = 0.0;
|
||||
let mut tilstand = vec![l.settpunkt_oppvarming; n_noder];
|
||||
let mut t_a_forrige = l.settpunkt_oppvarming;
|
||||
|
||||
@@ -215,6 +231,18 @@ pub fn simuler(l: &Lost, v: &Vaerdata, tilskudd: Systemtilskudd) -> Result<Times
|
||||
l.settpunkt_natt
|
||||
};
|
||||
|
||||
// ── uoppvarmede soner ───────────────────────────────────
|
||||
// Temperaturen følger av den stasjonære varmebalansen for sonen, med
|
||||
// varmetilskudd fra rør og bereder som står der. Romoppvarmingen fra forrige
|
||||
// time brukes, siden rørtapet følger varmeanleggets drift.
|
||||
let t_bakke_naa = bakketemp[crate::maaned_for_time(t)];
|
||||
for (i, sone) in l.soner.iter().enumerate() {
|
||||
let tilskudd = tilskudd.sone_fast.get(i).copied().unwrap_or(0.0)
|
||||
+ tilskudd.sone_andel_romvarme.get(i).copied().unwrap_or(0.0)
|
||||
* romvarme_forrige;
|
||||
t_soner[i] = sone.temperatur(t_a_forrige, t_ute, t_bakke_naa, tilskudd);
|
||||
}
|
||||
|
||||
// ── løsning ─────────────────────────────────────────────
|
||||
let prove = PROVEEFFEKT * l.bra;
|
||||
let ctrl = |s: &[f64]| -> f64 {
|
||||
@@ -238,8 +266,9 @@ pub fn simuler(l: &Lost, v: &Vaerdata, tilskudd: Systemtilskudd) -> Result<Times
|
||||
},
|
||||
t_ute,
|
||||
t_himmel,
|
||||
t_bakke: bakketemp[crate::maaned_for_time(t)],
|
||||
t_bakke: t_bakke_naa,
|
||||
t_a_forrige,
|
||||
t_soner: &t_soner,
|
||||
internlast,
|
||||
sol_gjennom,
|
||||
time: t,
|
||||
@@ -301,6 +330,7 @@ pub fn simuler(l: &Lost, v: &Vaerdata, tilskudd: Systemtilskudd) -> Result<Times
|
||||
tilstand[i] = los0[i] + andel * (los1[i] - los0[i]);
|
||||
}
|
||||
t_a_forrige = tilstand[0];
|
||||
romvarme_forrige = fi.max(0.0);
|
||||
|
||||
if skriv {
|
||||
ts.t_ute[t] = t_ute;
|
||||
@@ -318,6 +348,9 @@ pub fn simuler(l: &Lost, v: &Vaerdata, tilskudd: Systemtilskudd) -> Result<Times
|
||||
ts.internlast[t] = internlast;
|
||||
ts.sol_horisontal[t] = v.ghi[t];
|
||||
ts.vinduslufting[t] = h_luft / RHO_C_LUFT;
|
||||
for (i, v) in t_soner.iter().enumerate() {
|
||||
ts.sonetemperatur[i][t] = *v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,6 +369,7 @@ struct Kontekst<'a> {
|
||||
t_himmel: f64,
|
||||
t_bakke: f64,
|
||||
t_a_forrige: f64,
|
||||
t_soner: &'a [f64],
|
||||
internlast: f64,
|
||||
sol_gjennom: f64,
|
||||
time: usize,
|
||||
@@ -414,7 +448,10 @@ impl Kontekst<'_> {
|
||||
fn ytre_temperatur(&self, d: &Del) -> f64 {
|
||||
match d.mot {
|
||||
Mot::Grunn => self.t_bakke,
|
||||
Mot::Uoppvarmet => self.t_a_forrige - d.b_faktor * (self.t_a_forrige - self.t_ute),
|
||||
Mot::Uoppvarmet => match d.sone.and_then(|i| self.t_soner.get(i)) {
|
||||
Some(t) => *t,
|
||||
None => self.t_a_forrige - d.b_faktor * (self.t_a_forrige - self.t_ute),
|
||||
},
|
||||
Mot::Ute => {
|
||||
// Himmelandel etter flatens helning; resten ser bakken med utelufttemperatur.
|
||||
let f_himmel = (1.0 + d.helning.to_radians().cos()) / 2.0;
|
||||
@@ -463,6 +500,7 @@ fn bygg_deler(l: &Lost, v: &Vaerdata) -> Vec<Del> {
|
||||
kapasitet,
|
||||
glass: f.glass,
|
||||
mot: f.mot,
|
||||
sone: f.sone,
|
||||
b_faktor: f.b_faktor,
|
||||
absorptans: f.absorptans,
|
||||
helning: f.helning,
|
||||
|
||||
Reference in New Issue
Block a user