Data centres: multi-storey shell, racks and pods, cooling, fire safety, power
Deploy web Studio / deploy (push) Successful in 1m4s
Deploy web Studio / deploy (push) Successful in 1m4s
datacentre.rhai (palette groups Data centre, Cooling, Fire safety, Power): - dc_building: multi-storey shell (storeys of storey_h), walls in pieces, slabs, roof with parapet, louvres, front door and loading dock; levels cut it open storey by storey - raised_floor; rack_row and dc_pod (cabinets by U, width, depth, equipment, fill, doors, LEDs; in-row coolers; cold / hot aisle containment with vent tiles, roof, end doors, ceiling duct, airflow); dc_cage for colocation - crah, chiller (air-cooled, dry, adiabatic), cooling_tower, pipe_run - smoke_detectors (grid + coverage), fire_pipe (VESDA, sprinkler, gas), gas_bank (Novec 1230, FM-200, Inergen sized for its halls), fire_device (panels, call points, abort switches, beacons, extinguishers) - power_cab (UPS, battery, PDU, switchgear, RPP), busway, cable_tray, transformer - tooltips sum IT load, kW/m2, cooling redundancy per storey, UPS load, battery runtime, plant cooling and agent quantity (warning when short) Engine and stdlib: - part_hidden(o) in house.rhai: parts on closed storeys inside a dc_building are not drawn (they only made sort cycles under the slab above); house parts, furniture and people use it. Existing examples render byte-identical. - overhead services sort in their own "ceiling" layer with tight boxes - sort records which sprites each broken cycle involved; isokit check names them (Rendered.cycle_at) examples/datacentre (three storeys and a roof plant), Data centre demo in the web Studio, tests, SCRIPTING/README/ROADMAP, MCP instructions.
This commit is contained in:
1 parent
c8becc2e59
commit
2810477f1b
22 files changed
+2281
-18
No files matched your search
@@ -137,7 +137,17 @@ pub fn check(p: &Project) -> Vec<Finding> {
|
||||
));
|
||||
}
|
||||
if v.cycles > 0 {
|
||||
out.push(f("info", format!("{}/{rot}: {} depth-sort cycle(s) broken; split large sprites if something draws in front of what it stands behind", l.id, v.cycles), None));
|
||||
let mut at = v
|
||||
.cycle_at
|
||||
.iter()
|
||||
.take(3)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
.join("; ");
|
||||
if v.cycle_at.len() > 3 {
|
||||
at.push_str("; ...");
|
||||
}
|
||||
out.push(f("info", format!("{}/{rot}: {} depth-sort cycle(s) broken ({at}); split large sprites if something draws in front of what it stands behind", l.id, v.cycles), None));
|
||||
}
|
||||
for cls in v
|
||||
.html
|
||||
|
||||
@@ -201,6 +201,9 @@ pub struct View {
|
||||
pub sprites: usize,
|
||||
pub nodes: usize,
|
||||
pub cycles: usize,
|
||||
/// Where the depth sort broke its cycles ("a before b, c": sprite ids).
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub cycle_at: Vec<String>,
|
||||
pub warnings: Vec<String>,
|
||||
/// Object id -> world box [x0, y0, z0, x1, y1, z1].
|
||||
pub boxes: BTreeMap<String, [f64; 6]>,
|
||||
@@ -428,6 +431,7 @@ impl Project {
|
||||
sprites: r.sprites,
|
||||
nodes: r.nodes,
|
||||
cycles: r.cycles,
|
||||
cycle_at: r.cycle_at,
|
||||
warnings: r.warnings,
|
||||
boxes: built.boxes,
|
||||
ms: (t0.elapsed().as_secs_f64() * 1e4).round() / 10.0,
|
||||
|
||||
@@ -46,7 +46,17 @@ props.walk none/both/left/right adds raised sidewalks walk_w wide) ending on ano
|
||||
junction there (at any angle); a road_curve starts at its x, y heading along its rot, bends props.angle degrees \
|
||||
left or right on radius r and ends where the next road starts; two roads ending at one point make a mitred corner. \
|
||||
A roundabout (props.r ring radius, arm_e/n/w/s, arm_len) has its arm ends r + arm_len from its centre: put the \
|
||||
roads' ends exactly there, with the same width as road_d.";
|
||||
roads' ends exactly there, with the same width as road_d. \
|
||||
Data centres (categories Data centre, Cooling, Fire safety, Power): a dc_building (w x d, props.storeys) is the shell; \
|
||||
its storeys are the project parameter storey_h apart (5 m suits data halls) and levels gf, 1f, 2f cut it open. Put \
|
||||
every part on its storey (z = storey x storey_h) inside the walls (inner faces at w/2 - t and d/2 - t): a \
|
||||
raised_floor (w x d) per hall, then rack_row (fronts to local -y) and dc_pod objects (two rows round a contained aisle: \
|
||||
props.contain cold, hot or none; props.inrow adds an in-row cooler every n racks) on it, which stand on its top by \
|
||||
themselves; crah units along the walls; power_cab line-ups (UPS, battery, PDU, switchgear, RPP). Overhead runs \
|
||||
(cable_tray, busway, fire_pipe: VESDA, sprinkler or gas) take props.h above the slab: keep crossing runs at different \
|
||||
heights (busway 3.2, fibre 3.6, ladder 4.0, gas or sprinkler 4.25, VESDA 4.4, smoke_detectors 4.5 for 5 m storeys). \
|
||||
A gas_bank sizes its agent for the raised-floor halls on its storey; tooltips report IT load, cooling redundancy, \
|
||||
UPS load and battery runtime. Chillers and cooling towers go on the roof (z = storeys x storey_h) or in the yard.";
|
||||
|
||||
fn tool(name: &str, description: &str, props: Value, required: &[&str]) -> Value {
|
||||
json!({ "name": name, "description": description,
|
||||
|
||||
@@ -94,6 +94,45 @@ fn country_demo_renders_every_view_cleanly() {
|
||||
example_renders_every_view_cleanly("country");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn datacentre_demo_renders_every_view_cleanly() {
|
||||
let p = Project::load(Path::new(env!("CARGO_MANIFEST_DIR")).join("../../examples/datacentre"))
|
||||
.unwrap();
|
||||
assert!(p.runtime.is_ok(), "{:?}", p.runtime.as_ref().err());
|
||||
// storeys of 5 m; the building covers |x| <= 21, |y| <= 13 and has three
|
||||
// storeys, the plant on its roof (storey 3)
|
||||
let storey = |z: f64| ((z + 0.5) / 5.0).floor() as i64;
|
||||
for l in p.manifest.levels() {
|
||||
let k: i64 = match l.id.as_str() {
|
||||
"gf" => 0,
|
||||
"1f" => 1,
|
||||
"2f" => 2,
|
||||
_ => -1,
|
||||
};
|
||||
for rot in 0..4 {
|
||||
let v = p.render(&l.id, rot, None, false).unwrap();
|
||||
assert!(v.warnings.is_empty(), "{}/{rot}: {:?}", l.id, v.warnings);
|
||||
assert_eq!(v.cycles, 0, "{}/{rot}: {:?}", l.id, v.cycle_at);
|
||||
assert!(!v.html.contains("NaN"));
|
||||
for o in p.doc.objects.iter().filter(|o| o.kind != "group") {
|
||||
let s = storey(o.z);
|
||||
let ground = o.kind == "site" || o.kind == "area";
|
||||
let inside = !ground && o.x.abs() < 21.0 && o.y.abs() < 13.0;
|
||||
// the cut storey shows, closed storeys inside the shell and storeys above do not
|
||||
let shown = o.kind == "dc_building" || !inside || s == k || (k < 0 && s >= 3);
|
||||
assert_eq!(
|
||||
v.boxes.contains_key(&o.id),
|
||||
shown,
|
||||
"{} on {}/{rot}",
|
||||
o.id,
|
||||
l.id
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
assert!(check::check(&p).is_empty(), "{:?}", check::check(&p));
|
||||
}
|
||||
|
||||
fn example_renders_every_view_cleanly(name: &str) {
|
||||
let p = Project::load(
|
||||
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
|
||||
Reference in new issue
Block a user