Skip to content

Commit 7d54f70

Browse files
committed
Add roof and wall components for house visualization; refactor dew point calculations and utility functions
1 parent 226b536 commit 7d54f70

File tree

12 files changed

+759
-519
lines changed

12 files changed

+759
-519
lines changed

app/components/calculator/Calculator.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { StudWallSelector } from "./components/StudWallSelector"
1313
import { SortableTableRow } from "./SortableTableRow"
1414
import { WallVisualization } from "./WallVisualization"
1515
import { WallVisualization3D } from "./WallVisualization3D"
16-
import { DewPointCalculator } from "@/app/components/calculator/components/DewPointCalculator"
16+
import { calculateDewPoint } from "@/app/components/calculator/components/DewPointCalculator"
1717
import { useState } from "react"
1818
import { DewPointDisplay } from "./components/DewPointDisplay";
1919
import { TemperatureGradientDisplay } from "./components/TemperatureGradientDisplay"
@@ -53,9 +53,8 @@ export default function Calculator() {
5353
const [outsideTemp, setOutsideTemp] = useState(5);
5454
const [insideRH, setInsideRH] = useState(humidity);
5555
const [outsideRH, setOutsideRH] = useState(80);
56-
const dewPointCalculator = new DewPointCalculator();
5756

58-
const dewPoint = dewPointCalculator.calculateDewPoint(temperature, humidity);
57+
const dewPoint = calculateDewPoint(temperature, humidity);
5958

6059
const wallAssembly = {
6160
components,

app/components/calculator/WallVisualization3D.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Canvas } from '@react-three/fiber'
44
import { OrbitControls } from '@react-three/drei'
55
import { Geometry, Base, Subtraction } from '@react-three/csg'
66
import { WallComponent, commonMaterials, StudWallConfig } from "./types"
7-
import { TemperatureGradient } from "@/app/components/calculator/components/TemperatureGradient"; // Adjust alias if needed
7+
import { findDewPointPosition } from "@/app/components/calculator/components/TemperatureGradient";
88
import * as THREE from "three"; // NEW: Import THREE for DoubleSide
99

1010
interface WallVisualization3DProps {
@@ -181,12 +181,10 @@ export function WallVisualization3D({ components, studWallConfig, insideTemp, ou
181181
: undefined;
182182

183183
// Example temperature parameters (could be replaced with props)
184-
const tempGradient = new TemperatureGradient();
185-
186184
// NEW: Wrap dew point calculation with try-catch to handle invalid component values.
187185
let dewPointPosition;
188186
try {
189-
dewPointPosition = tempGradient.findDewPointPosition(components, insideTemp, outsideTemp, dewPoint);
187+
dewPointPosition = findDewPointPosition(components, insideTemp, outsideTemp, dewPoint);
190188
} catch (error) {
191189
console.error(error);
192190
dewPointPosition = null;
Lines changed: 11 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
1-
export class DewPointCalculator {
2-
private validateInputs(temperature: number, humidity: number): void {
3-
if (temperature < -40 || temperature > 60) {
4-
throw new Error('Temperature must be between -40°C and 60°C');
5-
}
6-
if (humidity < 0.01 || humidity > 100) {
7-
throw new Error('Relative humidity must be between 0.01% and 100%');
8-
}
1+
export function calculateDewPoint(temperature: number, humidity: number): number {
2+
if (temperature < -40 || temperature > 60) {
3+
throw new Error("Temperature must be between -40°C and 60°C");
94
}
10-
11-
calculateDewPoint(temperature: number, humidity: number): number {
12-
this.validateInputs(temperature, humidity);
13-
14-
// Magnus-Tetens formula constants
15-
const a = 17.27;
16-
const b = 237.7;
17-
18-
// Calculate gamma
19-
const gamma = ((a * temperature) / (b + temperature)) + Math.log(humidity / 100.0);
20-
21-
// Calculate dew point
22-
const dewPoint = (b * gamma) / (a - gamma);
23-
24-
return dewPoint;
5+
if (humidity < 0.01 || humidity > 100) {
6+
throw new Error("Relative humidity must be between 0.01% and 100%");
257
}
26-
}
8+
9+
const a = 17.27;
10+
const b = 237.7;
11+
const gamma = (a * temperature) / (b + temperature) + Math.log(humidity / 100);
12+
return (b * gamma) / (a - gamma);
13+
}
Lines changed: 76 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,140 +1,91 @@
11
import { WallComponent } from "@/app/components/calculator/types";
22

3-
export class TemperatureGradient {
4-
calculateTemperatures(
5-
components: WallComponent[],
6-
insideTemp: number,
7-
outsideTemp: number
8-
): number[] {
9-
// Replace error throw with a warning and default conductivity value.
10-
components.forEach(component => {
11-
if (component.conductivity <= 0) {
12-
console.warn(`Component with id ${component.id} has invalid conductivity. Using default conductivity value of 1.`);
13-
}
14-
});
3+
export function calculateTemperatures(components: WallComponent[], insideTemp: number, outsideTemp: number): number[] {
4+
const temperatures = [insideTemp];
5+
const totalR = components.reduce(
6+
(sum, comp) => sum + (comp.thickness / 1000) / (comp.conductivity > 0 ? comp.conductivity : 1),
7+
0
8+
);
9+
let currentR = 0;
1510

16-
const temperatures: number[] = [insideTemp];
17-
const totalR = components.reduce((sum, comp) =>
18-
sum + (comp.thickness / 1000) / (comp.conductivity > 0 ? comp.conductivity : 1), 0);
19-
20-
let currentTemp = insideTemp;
21-
let currentR = 0;
11+
for (const component of components) {
12+
const rValue = (component.thickness / 1000) / (component.conductivity > 0 ? component.conductivity : 1);
13+
currentR += rValue;
14+
temperatures.push(insideTemp - (currentR / totalR) * (insideTemp - outsideTemp));
15+
}
2216

23-
components.forEach(component => {
24-
const rValue = (component.thickness / 1000) / (component.conductivity > 0 ? component.conductivity : 1);
25-
currentR += rValue;
26-
currentTemp = insideTemp - (currentR / totalR) * (insideTemp - outsideTemp);
27-
temperatures.push(currentTemp);
28-
});
17+
return temperatures;
18+
}
2919

30-
return temperatures;
31-
}
32-
33-
calculateVaporPressureGradient(
34-
components: WallComponent[],
35-
insideTemp: number,
36-
outsideTemp: number,
37-
insideRH: number,
38-
outsideRH: number
39-
): number[] {
40-
const temperatures = this.calculateTemperatures(components, insideTemp, outsideTemp);
41-
const pressures: number[] = [];
42-
43-
// Calculate saturation vapor pressures at each temperature
44-
const saturationPressures = temperatures.map(temp =>
45-
610.7 * Math.pow(10, (7.5 * temp) / (237.3 + temp))
46-
);
47-
48-
// Calculate actual vapor pressures considering material resistance
49-
const totalResistance = components.reduce((sum, comp) =>
50-
sum + ((comp.vaporResistance || 1) * comp.thickness / 1000), 0);
51-
52-
const pInside = saturationPressures[0] * (insideRH / 100);
53-
const pOutside = saturationPressures[saturationPressures.length - 1] * (outsideRH / 100);
54-
55-
pressures.push(pInside);
56-
57-
let currentPressure = pInside;
58-
let currentResistance = 0;
20+
export function calculateVaporPressureGradient(
21+
components: WallComponent[],
22+
insideTemp: number,
23+
outsideTemp: number,
24+
insideRH: number,
25+
outsideRH: number
26+
): number[] {
27+
const temperatures = calculateTemperatures(components, insideTemp, outsideTemp);
28+
const saturationPressures = temperatures.map((temp) => 610.7 * Math.pow(10, (7.5 * temp) / (237.3 + temp)));
29+
const totalResistance = components.reduce((sum, comp) => sum + (comp.vaporResistance || 1) * (comp.thickness / 1000), 0);
30+
const pInside = saturationPressures[0] * (insideRH / 100);
31+
const pOutside = saturationPressures[saturationPressures.length - 1] * (outsideRH / 100);
32+
const pressures = [pInside];
33+
let currentResistance = 0;
5934

60-
components.forEach((component, index) => {
61-
const resistance = (component.vaporResistance || 1) * component.thickness / 1000;
62-
currentResistance += resistance;
63-
currentPressure = pInside - (currentResistance / totalResistance) * (pInside - pOutside);
64-
pressures.push(currentPressure);
65-
});
35+
for (const component of components) {
36+
const resistance = (component.vaporResistance || 1) * (component.thickness / 1000);
37+
currentResistance += resistance;
38+
pressures.push(pInside - (currentResistance / totalResistance) * (pInside - pOutside));
39+
}
6640

67-
return pressures;
68-
}
69-
70-
checkCondensationRisk(
71-
temperatures: number[],
72-
dewPoint: number,
73-
components: WallComponent[]
74-
): { hasRisk: boolean; riskLayers: number[]; vaporPressureRisk: boolean; saturationPoints: number[] } {
75-
const riskLayers: number[] = [];
76-
const saturationPoints: number[] = [];
77-
let hasRisk = false;
78-
let vaporPressureRisk = false;
41+
return pressures;
42+
}
7943

80-
// Calculate saturation vapor pressures
81-
const saturationPressures = temperatures.map(temp =>
82-
610.7 * Math.pow(10, (7.5 * temp) / (237.3 + temp))
83-
);
44+
export function checkCondensationRisk(
45+
temperatures: number[],
46+
dewPoint: number,
47+
components: WallComponent[]
48+
): { hasRisk: boolean; riskLayers: number[]; vaporPressureRisk: boolean; saturationPoints: number[] } {
49+
const riskLayers: number[] = [];
50+
const saturationPoints: number[] = [];
51+
const saturationPressures = temperatures.map((temp) => 610.7 * Math.pow(10, (7.5 * temp) / (237.3 + temp)));
52+
const actualPressures = calculateVaporPressureGradient(components, temperatures[0], temperatures[temperatures.length - 1], 50, 80);
8453

85-
const actualPressures = this.calculateVaporPressureGradient(
86-
components,
87-
temperatures[0],
88-
temperatures[temperatures.length - 1],
89-
50,
90-
80
91-
);
54+
for (let i = 1; i < temperatures.length - 1; i++) {
55+
if (temperatures[i] <= dewPoint) riskLayers.push(i - 1);
56+
if (actualPressures[i] >= saturationPressures[i]) saturationPoints.push(i - 1);
57+
}
9258

93-
// Skip first temperature (interior interface point)
94-
for (let i = 1; i < temperatures.length - 1; i++) {
95-
if (temperatures[i] <= dewPoint) {
96-
hasRisk = true;
97-
// Adjust index to match component array (subtract 1 because temperatures array includes interior point)
98-
riskLayers.push(i - 1);
99-
}
59+
return {
60+
hasRisk: riskLayers.length > 0,
61+
riskLayers,
62+
vaporPressureRisk: saturationPoints.length > 0,
63+
saturationPoints,
64+
};
65+
}
10066

101-
if (actualPressures[i] >= saturationPressures[i]) {
102-
vaporPressureRisk = true;
103-
// Adjust index here as well
104-
saturationPoints.push(i - 1);
105-
}
106-
}
67+
export function findDewPointPosition(
68+
components: WallComponent[],
69+
insideTemp: number,
70+
outsideTemp: number,
71+
dewPoint: number
72+
): number | null {
73+
const positions = [0];
74+
let totalThickness = 0;
75+
for (const component of components) {
76+
totalThickness += component.thickness / 1000;
77+
positions.push(totalThickness);
78+
}
10779

108-
return { hasRisk, riskLayers, vaporPressureRisk, saturationPoints };
80+
const temperatures = calculateTemperatures(components, insideTemp, outsideTemp);
81+
for (let i = 0; i < temperatures.length - 1; i++) {
82+
const tStart = temperatures[i];
83+
const tEnd = temperatures[i + 1];
84+
if ((tStart >= dewPoint && tEnd <= dewPoint) || (tStart <= dewPoint && tEnd >= dewPoint)) {
85+
const ratio = (tStart - dewPoint) / (tStart - tEnd);
86+
return positions[i] + ratio * (positions[i + 1] - positions[i]);
10987
}
88+
}
11089

111-
findDewPointPosition(
112-
components: WallComponent[],
113-
insideTemp: number,
114-
outsideTemp: number,
115-
dewPoint: number
116-
): number | null {
117-
// Calculate cumulative positions in meters
118-
const positions = [0];
119-
let totalThickness = 0;
120-
components.forEach(component => {
121-
totalThickness += component.thickness / 1000;
122-
positions.push(totalThickness);
123-
});
124-
125-
// Calculate temperatures at boundaries
126-
const calculatedTemps = this.calculateTemperatures(components, insideTemp, outsideTemp);
127-
128-
// Find segment where dewPoint is reached (assuming insideTemp > outsideTemp)
129-
for (let i = 0; i < calculatedTemps.length - 1; i++) {
130-
const tStart = calculatedTemps[i];
131-
const tEnd = calculatedTemps[i + 1];
132-
if ((tStart >= dewPoint && tEnd <= dewPoint) || (tStart <= dewPoint && tEnd >= dewPoint)) {
133-
const ratio = (tStart - dewPoint) / (tStart - tEnd);
134-
const dewPos = positions[i] + ratio * (positions[i + 1] - positions[i]);
135-
return dewPos;
136-
}
137-
}
138-
return null;
139-
}
90+
return null;
14091
}

0 commit comments

Comments
 (0)