Building data for flood, wind and earthquake checks
Takes room floor heights, opening sills, storey heights, areas, widths and masses from the model for the hazard checks.
How the precision is kept
Elevations and sills are millimeters in the model and are divided by 1000 in 64-bit. A storey's mass is its footprint area times the mass per square meter the person gives (500 kg/m² by default) and uses the unrounded area. The area and the width across the wind kept in the storey record are rounded to two decimals.
Calculations under this policy
3 calculations in 1 source file. The code is read from the released app when this page loads. It is the calculation people run, not a copy kept for this page.
One subtraction and one division by 1000 per value, in 64-bit. A negative sill is set to 0; a stair joins its two rooms with a sill of 0.
hazard-model.js
lines 18 to 27
BimCraft 0.8.1
export function floodScene(ed) {
const { w, levels, rooms, doors, stairs, notes } = modelLinks(ed);
if (!levels.length) return { rooms: [], openings: [], notes };
const datum = levels[0].elevation, elev = new Map(levels.map((l) => [l.guid, (l.elevation - datum) / 1000]));
const out = rooms.map((r) => ({ id: r.id, name: r.name, level: r.level, levelName: r.levelName, floor: elev.get(r.level), area_m2: r.area_m2, poly: r.poly }));
const at = attachDoors(rooms, doors), byId = new Map(doors.map((d) => [d.id, d]));
const openings = at.map((o) => { const d = byId.get(o.id); return { id: o.id, a: o.rooms[0], b: o.rooms[1], sill: Math.max(0, (d.sill || 0)) / 1000, kind: d.kind }; }); // a door's or window's sill is measured from its own level's floor
for (const s of stairs) openings.push({ id: s.id, a: s.a.room, b: s.b.room, sill: 0, kind: 'stair' });
return { rooms: out, openings, datum_mm: datum, notes };
}
Storey height, area, width and mass
64-bit
The storey data the wind and earthquake checks use, from the model's levels and outlines.
area = Σ |outline area| ÷ 1e6; h = (next elevation − elevation) ÷ 1000; z = (elevation − datum) ÷ 1000 + h ÷ 2; mass = area × mass per m²; T1 = 0.1 × storeys when not given
The mass uses the unrounded area. The storey record keeps the area rounded to 0.01 m² and the width as Math.round(ext ÷ 10) ÷ 100, that is 0.01 m.
hazard-model.js
lines 29 to 48
BimCraft 0.8.1
export function hazardBuilding(ed, { massPerM2 = 500, T1 = null, dir = 'x' } = {}) {
const { w, levels, rooms, notes } = modelLinks(ed);
if (!levels.length) return { storeys: [], notes };
const datum = levels[0].elevation, storeys = [];
levels.forEach((lv, i) => {
const loops = storeyLoops(w, lv.id), outs = (loops.outlines || []).filter((o) => o.poly && o.poly.length > 2);
const mine = rooms.filter((r) => r.level === lv.guid);
const area = outs.length ? outs.reduce((s, o) => s + Math.abs(o.area) / 1e6, 0) : mine.reduce((s, r) => s + r.area_m2, 0);
const pts = (outs.length ? outs.flatMap((o) => o.poly) : mine.flatMap((r) => r.poly));
if (!pts.length) return;
const xs = pts.map((p) => p[0]), ys = pts.map((p) => p[1]);
const ext = dir === 'x' ? Math.max(...ys) - Math.min(...ys) : Math.max(...xs) - Math.min(...xs);
const next = levels[i + 1], h = (next ? next.elevation - lv.elevation : lv.height) / 1000;
storeys.push({ name: lv.name, guid: lv.guid, z: (lv.elevation - datum) / 1000 + h / 2, h, area_m2: Math.round(area * 100) / 100, width_m: Math.round(ext / 10) / 100, mass: area * massPerM2 });
});
if (!storeys.length) return { storeys: [], notes };
const m = storeys.map((s) => s.mass), T = T1 > 0 ? T1 : 0.1 * storeys.length; // the rule of thumb of a tenth of a second a storey, until the person gives the period
const k = uniformFor(m, T), building = shearBuilding({ m, k: m.map(() => k) });
return { storeys, m, k, T1: T, assumedT1: !(T1 > 0), building, notes, height: storeys.reduce((s, x) => s + x.h, 0) };
}
Storey data from the analysis frame
64-bit
The same storey data when the stiffness comes from the structural frame instead of a typed period.
z = (floor z − base) ÷ 1000 − h ÷ 2; width = extent of the nodes within 150 mm of the floor
Floor heights, masses and the period come from the frame model (hazard-frame.js). Nodes are assigned to a floor with an absolute 150 mm tolerance; area and width are rounded to two decimals.
hazard-model.js
lines 50 to 64
BimCraft 0.8.1
/**
* 0.8 EG.47 (bim-sim_PART_3): the same `hazardBuilding` shape, but the stiffness comes from the Analysis tab's frame (hazard-frame.js) instead of one period the person
* types: hazardFrameBuilding(frameModel, ed?, { addKgM2, dir }) → { storeys, building, T1, source: 'frame', ... } | { storeys: [], reason, notes }.
* Storey names are the model's levels when their count matches the frame's floors; else "Floor n". Mass = the members' weight + addKgM2 × the floor's plan box.
*/
export function hazardFrameBuilding(frameModel, ed = null, { addKgM2 = 500, dir = 'x' } = {}) {
const fb = frameBuilding(frameModel, { dir, addKgM2 });
if (!fb.ok) return { storeys: [], reason: fb.reason, notes: fb.notes || [] };
let names = null;
if (ed) { try { const lv = modelLinks(ed).levels; if (lv.length - 1 === fb.floors.length || lv.length === fb.floors.length) names = lv.slice(lv.length - fb.floors.length).map((l) => l.name); } catch (e) { names = null; } }
const ext = (nodes) => { const v = nodes.map((i) => frameModel.nodes[i]), a = dir === 'x' ? v.map((n) => n.y) : v.map((n) => n.x); return Math.max(...a) - Math.min(...a); };
const storeys = fb.floors.map((f, i) => ({ name: names ? names[i] : 'Floor ' + (i + 1), z: (f.z - fb.base) / 1000 - f.h / 2, h: f.h, area_m2: Math.round(f.area_m2 * 100) / 100, width_m: Math.round(ext(frameModel.nodes.map((n, k) => k).filter((k) => Math.abs(frameModel.nodes[k].z - f.z) <= 150)) / 10) / 100, mass: f.mass }));
const T1 = fb.modes[0].period;
return { storeys, m: fb.m, k: fb.k, T1, assumedT1: false, building: fb, notes: fb.notes, height: storeys.reduce((s, x) => s + x.h, 0), source: 'frame' };
}
In detail
Method
z = height of the storey's middle above the lowest floor; mass = area × mass per m²; width = extent of the footprint across the wind direction. With no period given, T1 = 0.1 s × the number of storeys, and one stiffness for every storey is derived from it (uniformFor in hazard.js).
Number types
64-bit numbers.
Tolerances
Frame nodes within 150 mm of a floor's height count as on that floor (absolute).
Limits
The width is rounded to 0.01 m and the area to 0.01 m² in the record handed on. The default period is a rule of thumb and the result says it was assumed.
Approach: 64-bit, direct
Every value is a 64-bit number from input to result. Formulas are closed form or a direct solve, and every comparison uses a stated tolerance.