Skip to main content
Glama
akontadakis
by akontadakis

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
PYTHONPATHNoOnly for a local clone launched from source — set to the src dir. Default: —.
SMARTSPATHNoSMARTS executable — the file, not its directory. Default: unset (SMARTS engine unavailable).
HCL_WORK_ROOTNoDirectory where simulation files are written. Default: first MCP client root, else ~/hcl_work.
HCL_DAYSIM_BINNoDaysim bin directory (ds_shortterm, epw2wea). Default: auto-discovered on PATH.
HCL_RADIANCE_BINNoRadiance bin directory, if not on PATH. Default: auto-discovered on PATH.

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
extensions
{
  "io.modelcontextprotocol/ui": {}
}
completions
{}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
spd_to_channelsA

Average a spectral power distribution into the 3- or 9-channel bins.

spd: a .spd file path, 2-column text, or list of [wavelength, value]. channel_type: 0=3ch [r,g,b], 1=9ch [b1..r3]. The str|list annotation is load-bearing: an untyped arg makes FastMCP stringify a list-of-pairs over the wire, which parse_spd then mis-reads as 2-column text (DEF-1/DEF-2 class).

glass_transmissivityA

Convert glazing transmittance (0-1) to Radiance transmissivity. Accepts a number or list.

Transmittance (Tvis, the datasheet number) and transmissivity (the value a Radiance glass primitive takes) are NOT the same: transmissivity is always the larger, e.g. 0.70 -> 0.763.

USE THIS ONLY when hand-writing a Radiance glass primitive. Do NOT pre-convert for write_material(material_type=0) or for an import_geometry material_map {"type": "glass", "tvis": ...} -- both run this same conversion internally, so feeding them 0.763 yields 0.831 (~9% high) and silently inflates every downstream daylight and mel-EDI result. Those two take the raw datasheet Tvis.

The float|list annotation is load-bearing: without it FastMCP emits an empty arg schema and delivers the value as a string, so the core's transmittance-squared term would raise (DEF-1).

write_materialC

Write Radiance material .rad file(s). material_type 0=glass,1=plastic. Honors client roots for work_dir.

circadian_metricsA

Photopic / melanopic / neuropic equivalent illuminance from channel irradiances.

Returns one metrics dict for a single point, or a list of dicts for many points. Each carries BOTH melanopic_lux (a melanopic-weighted illuminance) and mel_edi (CIE S 026 melanopic equivalent daylight illuminance) — they are different quantities, and the circadian standards are written in mel-EDI, so pass mel_edi to compliance, never melanopic_lux.

spd: the SOURCE spectrum feeding these channels, when known (.spd path, 2-column text, or [[nm, value], ...]). It is the spectrum at the LAMP, and mel_der is always reported at the POINT: supplying it keeps the source's within-bin structure, which the channel averages cannot represent, and combines it with the per-bin transport the channels reveal. Two extra fields come with it — source_mel_der (the source's own) and transport_ratio (the two divided), so a room that shifts the spectrum is visible rather than folded away. Without an SPD, mel-DER is inferred from the channel averages alone: exact for D65, within ~1.5% for smooth spectra, up to ~8% high for a narrow-band fluorescent. mel_der_source records which route ran.

alpha_opicA

CIE S 026 alpha-opic E/ELR/EDI. Provide spd (exact-spectrum route) OR channels (binned route).

spd accepts a .spd file path, 2-column text, or a list of [wavelength, value]. alpha: 1=S,2=M,3=L,4=rhodopic,5=melanopic; omit for all five.

For the spd path, a scale_warning key is attached (CORE-3): non-None when the SPD looks RELATIVE/normalized (peak <= 1.5) and the E/EDI values are shape indicators rather than lux-scale, else None. The channel path is unaffected.

validateB

Run the built-in correctness self-test (weight sums, alpha-opic guards).

spectral_metricsA

Derived HCL quantities from an SPD: cct/duv, mel-DER, mel/photopic ratio, and EML<->EDI.

spd accepts a .spd file path, 2-column text, or a list of [wavelength, value]. The two modes below are mutually exclusive, so the eml_edi key has a DIFFERENT shape in each:

  • spd= -> {cct_duv, mel_der, mel_photopic_ratio, eml_edi:{mel_edi, eml}}. Here eml_edi is the SPD's melanopic EDI + its EML equivalent. NOTE: the eml_edi block is ABSOLUTE/scale-dependent (see its scale_note); the other metrics are scale-invariant. metric ('all' | one key) selects a single block.

  • eml_edi_value= -> scalar EML<->mel-EDI conversion only (no SPD needed): {eml_edi:{input, direction, result}}. eml_edi_direction= 'medi_to_eml' (default) or 'eml_to_medi'. (Spec 7.1 row 5 EML<->EDI.)

complianceA

Check a value against a lighting standard.

standard: well_v2_l03 | brown_2022 | iso_cie_8995_1_2025 | en_17037 | en_12464_1 | ul_24480.

CIRCADIAN standards are scored on mel_edi (CIE S 026 mel-EDI -- NOT melanopic_lux, which is larger by D65's melanopic/photopic ratio ~1.10 and would silently relax the threshold); eml is accepted and converted. EML is the LARGER number -- EML = mel-EDI * 1.103 -- so an eml input is DIVIDED by 1.103 to score it. Pass ONE of them: if both are given, mel_edi wins, eml is discarded without warning, and the result is stamped quantity "mel_edi" with no trace of the ignored input. To go the other way, from mel-EDI to EML, use spectral_metrics(eml_edi_value=..., eml_edi_direction='medi_to_eml'); do not do the arithmetic by hand. en_17037 returns "n/a" (daylight-provision, non-circadian) and ul_24480 returns "unsupported" (Circadian Stimulus, not computed here).

standard="en_12464_1" is the ELECTRIC VISUAL-TASK path and ignores mel_edi entirely: pass task (see EN_12464_1_TASKS / the hcl://compliance/en_12464_1 resource) plus the measured em/ugr/uo/ra, and optionally the surround/background (em_surround, uo_surround, em_background, uo_background) and wall/ceiling/cylindrical (em_wall, uo_wall, em_ceiling, uo_ceiling, em_cylindrical, uo_cylindrical) values -- each relationship is evaluated only when supplied. Supplying the task but no measured values returns "incomplete", never a vacuous "pass".

presetsA

List available illuminant presets (CIE standards + illustrative LED models), or fetch one by name.

Names: D65, D50, A, FL1..FL12, and the illustrative LED models LED_3000K/4000K/5000K/BLUEPUMP/VIOLETPUMP (flagged illustrative, not measured - see spec 5.7). Returns SPD + metadata when a name is given.

colored_skyA

Generate a colored Perez sky+sun Radiance definition.

mode 'spectra' (per-channel spectral scaling, runs gendaylit) or 'luminance' (Radiance -C built-in coloring, 3-channel only, pure emit). irrad_mode 'W' (direct+diffuse) or 'E' (global). diffuse_channels/direct_channels: 3 or 9 channel values (from spd_to_channels); ignored in luminance mode. lon is standard signed / EAST-positive (Seattle = -122.3, Athens = 23.73), matching raw EPW.

SOLAR POSITION. By default the sun is derived by gendaylit's own ephemeris from month/day/hour + lat/lon/utc, and hour is read as a WALL-CLOCK instant. spectral_sky_from_epw's hour is a different thing — an EPW hour-ENDING label, whose geometry is evaluated at the mid-interval instant (hour - 0.5) because the row's DNI/DHI are averaged over the preceding hour. Passing the same integer to both therefore puts the spectrum and the traced sky half an hour (7.5 deg of diurnal arc) apart, with no error raised.

To keep them on one instant, pass that record's geometry through here VERBATIM: sun_zenith_deg = record["geometry"]["zenith_deg"] sun_azimuth_deg = record["geometry"]["azimuth_deg"] Both are required together; supplied, they emit gendaylit's -ang form and make the record's position authoritative for the traced geometry. Omitted, behaviour is unchanged.

colored_luminaireA

Inject a channel triplet into a luminaire .rad, writing a NEW file (never edits the input).

count: 0=blue,1=green,2=red third of 9 values. The colored definition is written to work_dir (client-roots aware) as .rad — the source rad_path is left untouched — and its absolute path is returned. rad_path may be a .rad file path or raw .rad text. Returns {file, rad}.

referenceB

Look up HCL reference content. topic: bins | coefficients | caveats | overview.

run_gridB

Point-in-time grid HCL metrics via Radiance (oconv -> rtrace -I per channel -> recombine).

scene_sets: 1 list of .rad paths for 3-channel, or 3 lists (blue/green/red bin sets) for 9-channel. points: rows [x,y,z,dx,dy,dz] or a .pts path. Runs Radiance if present, else returns the commands. export_csv: optional path (abs or relative to work_dir) to dump the per-point result table.

sky_files: which scene paths are sky, listed exactly as they appear in scene_sets. Only matters with electric_lights, which builds a sky-free octree for the electric block. Left unset, the sky is DETECTED (gensky/gendaylit primitives, skyfunc, the sky/ground hemispheres, plus a basename hint), which covers the generators this codebase and Radiance use but cannot cover a hand-rolled sky using none of them. Pass it explicitly for an unusual scene — in both directions: to name a sky nothing would detect, or to KEEP a sky-looking file (exterior context) inside the electric octree. A leak here reports daylight as electric light; the electric block carries a lumen_bound (sum of luminaire lumens / grid area) so an over-count is visible.

run_imageC

Fisheye HCL image workflow: rpict -> mel/neuropic greyscale luminance maps (falsecolor-ready) -> optional ipRGC FOV weighting -> RGB-from-HDR eye irradiance. Runs Radiance if present, else returns the commands.

import_geometryA

Import a Wavefront .obj room into a per-channel Radiance scene (obj2rad -> xform).

material_map: {group_name: spec} keyed by OBJ usemtl (else g) names; unmapped groups hard-fail. spec is a library-name string (illustrative reflectance) or a dict {"type": "plastic"|"glass"|"ground"|"context"|"luminaire"|"floor", "refl"/"tvis": float, ...}: plastic=opaque diffuse; glass=transmitting; ground=opaque + drives ground_albedo; context=exterior shading (in oconv, excluded from sensor footprint/room-sanity); luminaire=marker + IES (-> electric_lights); floor=opaque + anchors the sensor footprint. units: mm|cm|m|ft. up_axis: Y|Z.

v2/v3 parameters:

  • north_angle_deg: clockwise azimuth (degrees) that post-remap +Y points toward; applied as -rz(-north) after up-axis correction.

  • dry_run=True: return a discovery payload (groups, bbox_m, mesh_quality, suggestions) without binding materials or running Radiance. material_map not required in dry_run mode.

  • sidecar: path to a JSON file supplying defaults (explicit kwargs always win over sidecar).

  • derive_sensors: derive a work-plane grid + eye-level observer_sets (at BOTH seated 1.2 m and standing 1.6 m by default) + DGP-view strings from the geometry.

  • eye_heights / workplane_h / spacing: tune the derived-sensor layout (defaults (1.2, 1.6) / 0.8 / 0.6).

  • annotate: build a colored-by-material falsecolor render (oconv -> rpict -> falsecolor; live-validated).

  • strict: raise GeometryHealthError when the embedded health report (result["health"]) holds error-severity findings (e.g. coincident surfaces), instead of returning a report that looks plausible but is built on defective geometry. strict has NO effect when dry_run=True: the dry_run path returns before materials are bound, so no health report is computed to raise on.

Returns geometry_set + material_sets (index-aligned per channel-set) to compose into run_grid / run_annual scene_sets, plus discovered groups and warnings, an always-present apertures report, and a provenance manifest (written as a manifest.json sidecar -> manifest_path, and embedded as a #-comment header in each geometry .rad). Conditional keys appear only when their feature is mapped/requested: ground_albedo/ground_albedo_kind (a 1-nm albedo from any type:"ground" group -> feed to spectral_sky_from_epw(spectral_albedo=...)); electric_lights (drop-in luminaire payload for run_grid/run_image, which run ies2rad + colorize); context_groups (type:"context" exterior-shading groups); and grid_points/observer_sets/observer_points/glare_views (derive_sensors).

check_geometryA

Health-check an OBJ scene without building it (spec 2026-07-23).

Reports geometry defects that would otherwise complete silently and return a plausible number: coplanar surfaces (Radiance z-fighting), glazing with no opening cut in the wall, duplicated and non-planar faces, an unclosed enclosure. Every error and warning carries a fix. Categories not yet implemented appear in skipped, so an absent category never reads as clean.

Needs no Radiance binaries and builds no scene, so it is cheap to re-run while fixing a model. import_geometry embeds the same report as result["health"].

radiance_statusA

Report Radiance availability: {available, bin_dir, version, found, missing}.

Use this to check whether Radiance tools (run_grid, ...) will execute vs return commands.

weatherB

Ingest a .wea (DNI/DHI per timestamp) and/or decompose an analysis period into HOY + wea line numbers.

Returns wea_summary (record count, first/last timestamp, DNI/DHI ranges) rather than the full per-hour arrays — those reach up to 8760 rows and overflow the response budget. Use period + subset_out to get the rows you actually need (HOY/wea_lines in decomposed, the subset .wea on disk).

run_annualA

Annual 2-phase DDS HCL simulation (per channel) -> annual mel-EDI + circadian dosimetry.

channel_scenes: 1 dict (3ch) or 3 dicts (9ch), each {materials:[paths], geometry:path, sky_color:[r,g,b]}. NOTE each dict's geometry is a SINGLE .rad path (geometry_set[i] from import_geometry), not the whole geometry_set list. points: inline [x,y,z,dx,dy,dz] rows OR a .pts path (inline rows are written to a .pts for you, matching run_grid). period: optional [[m,d,h],[m,d,h]] analysis window; when given, the .wea is subset to that period before the run and real HOY drives dosimetry (omit to run the full year). Runs Radiance if present, else returns the exact command sequence.

nvrdA

Light-driven alerting response over time (Amundadottir nvRD).

spectral_series: per-timestep spectral irradiance rows (311 pts 390-700 nm, or 401 pts 380-780) as an inline list, OR a path to a text/CSV file with one row per line. PREFER THE FILE PATH for large/full-resolution series: a big inline array can be truncated over the MCP wire (e.g. 401-pt rows arriving as 367) and then fail the row-length check. Rows must be a SINGLE point+view orientation, in CHRONOLOGICAL order, ideally uniformly spaced at timestep_h. Pre-group multi-orientation/multi-day data and call once per orientation (§9.4 — the source's automatic per-orientation grouping is not reproduced in v1). timestep_h: hours per step. Must be <= 0.3 and yield odd nvRD filter lengths; the model is validated at 0.1 (= 6 min), the recommended value. Other steps raise ValueError. You supply the series (no Daysim). hours: optional explicit per-timestep hour vector for non-uniform spacing; must be monotonically non-decreasing. When omitted, a uniform grid (i*timestep_h) is used. Returns effective_irradiance, relative_response, and cumulative_response per timestep.

ies_analyzeA

Parse an IESNA LM-63 luminaire and return its photometric report (rated lumens, watts, efficacy, max candela + location, beam/field angles, zonal flux down/up, LOR).

ies: raw IES text or a file path.

ies_to_radianceB

Convert an IES luminaire to a Radiance .rad via ies2rad, optionally placed via xform.

-m carries user scaling only (multiplier * maintenance_factor); ies2rad applies the IES candela/ballast/pfactor itself. Runs ies2rad if Radiance is present, else returns the commands.

glare_ugrC

Render a fisheye (daylight and/or electric_lights) and run evalglare -> UGR/DGP/glare sources.

Delegates to run_image with glare=True. Runs Radiance if present, else returns the commands.

lighting_controlsA

Daylight-responsive lighting-control calculator (EnergyPlus §7.3.5; verified vs elec_lights.xlsx).

Point-in-time: pass itot_per_point=[lx at each reference point] -> {fL, fP, FP, P_elec, P_saved, reduction}. Annual/series: pass itot_series=[[lx per point] per hour] + area -> {per_hour, annual_kwh, annual_kwh_per_m2, mean_FP, mean_reduction, occupied_hours}. weights are the per-point area weights (e.g. from area_weights_from_geometry). control_type: ContinuousOff (default) | Continuous | Stepped. workbook_compat=True reproduces the elec_lights.xlsx off-gates (regression).

daylight_savingsA

Automated daylight-responsive savings: daylight sim at the reference points -> lighting_controls.

mode='point_in_time' uses run_grid (scene_sets + points; supports multiple reference points); mode='annual' uses run_annual_daylight (channel_scenes + wea + points, 8760 h) and supports a multi-point grid (one weight per reference point) via points=[...] or sensor_set='name'. run=False emits the command plan without executing. An annual run elicits confirmation first (it is long); decline -> the emitted plan is returned.

weights: one per reference point, interpreted as that daylight zone's FLOOR-AREA FRACTION, so they must sum to <= 1.0 (NOT one-per-zone full-power flags -- e.g. [1, 1] is invalid; use [0.4, 0.3] etc.). The leftover (1 - Σweights) is the uncontrolled core area billed at full power. For a single point pass [1.0]. Compute proper fractions with hcl_core.lighting_controls.area_weights_from_geometry(width, length, window_head, task_height).

Return shapes: {"ran": False, ...commands...} (not executed); {"ran": True, "error": ..., "failed_step": ...} (a Radiance step failed mid-run); else {"ran": True, "mode": ..., "controls": ...} on success.

Note: in annual mode with schedule=None, the default weekday 08:00-18:00 mask is built to the length run_annual returns and assumes an 8760-h, Monday-anchored (HOY 0 = Mon 00:00) series. If run_annual is run over a sub-period or a non-Monday-anchored year, pass an explicit schedule.

annual_daylightB

Annual climate-based daylight metrics on the grid: per-point DA/cDA/UDI + spatial sDA/ASE.

channel_scenes: 1 dict (3ch) or 3 dicts (9ch), each {materials:[paths], geometry:path, sky_color:[r,g,b]} -- same shape as run_annual. points: inline rows or a .pts path; OR pass sensor_set='name' (created via the sensors tool). ASE uses a dedicated direct-only (-ab 0) pass. occupancy: optional per-timestep 0/1 mask (defaults to weekday occupied_start..end, Monday-anchored 8760-h). Runs Radiance if present, else returns the command sequence.

shading_model: declare the scene's operable shading -- 'none' (no device modelled), 'modelled' (a device is in the geometry) or 'lm83_default_blind'. The returned sDA_basis block records it alongside the analysis period and says whether the sDA key is an LM-83 sDA or only the underlying DA-based spatial fraction. Left undeclared it reports 'undeclared' and lm83_conformant: false -- the metric is never assumed conformant.

lm83_daylightA

IES LM-83-12 sDA(300/50%) and ASE(1000,250h) with MANDATORY operable blinds.

Unlike annual_daylight, which computes the arithmetic of sDA/ASE on whatever shading the scene happens to contain, this runs LM-83's method: a three-phase (V.T.D.s) engine per window group, an hourly blind that closes when 2.2.6's direct-sun trigger fires, and a zero-bounce ASE pass with blinds retracted and no sky or ground (3.2.6, 3.3).

obj_path + material_map: the same OBJ room and material mapping import_geometry takes. Glazing must be mapped {"type": "glass", "tvis": ...} -- window groups are formed from those faces, and with no glass face there is no window to operate.

units (mm|cm|m|ft) and up_axis (Y|Z) describe the OBJ, defaulting to metres and Z-up; north_angle_deg is the clockwise azimuth post-remap +Y points toward. These decide the facade azimuths that window grouping keys on, so a wrong up_axis silently regroups the windows.

points: inline rows or a .pts path, OR sensor_set='name'. Grid spacing, workplane height and wall offset are MEASURED from these coordinates and reported, never accepted as parameters.

areas: 2.2.6 trigger areas, [{name, area_m2, point_indices}], split by facade orientation and each under 10,000 sf -- the trigger must hold in EVERY area, and pooling facades dilutes the fraction so blinds close later than the standard requires. Omit and pass floor_area_m2 to get a single whole-grid area, which is only correct for a single-facade space. An area over 10,000 sf is refused before any Radiance runs.

blind: the operable shade, per 2.2.7. Omitted -> the unknown-shade default of 5% diffuse VLT. {"shade_type": "fabric", "vlt": .., "openness": ..}, {"shade_type": "louver", "reflectance": >0.8} for the 20% white-louver branch, or {"bsdf": "path.xml"} for a measured Klems file. Note the default is 5%, NOT 20% -- the 20% figure is the louver branch and needs a declared reflectance.

window_groups: optionally declare grouping instead of auto-clustering by azimuth and plane, [{name, face_indices, role}] with role 'view' or 'clerestory' -- 2.2.6 asks that view groups close before clerestory ones, and role cannot be inferred from azimuth.

declared_no_blinds: assert the design documents state no blinds (2.2.6's escape clause). Reported as a per-group condition; it never replaces the headline, which always operates blinds.

Returns metrics (sDA, ASE, per_point_DA, conditions) plus blind_hours and the window groups. The conformance flag is lm83_method_conformant and is presently ALWAYS FALSE: 2.2.8-2.2.11's model-input clauses (dirt depreciation, frame occlusion, reveals, obstructions, interior reflectance defaults, mandatory furniture) are out of scope, so glazing runs at its raw tvis and sDA is biased upward -- roughly 32% of transmitted flux on an unknown-frame vertical window. Read metrics.conditions.departures before quoting a number; this is not by itself an LM-83 or LEED submission.

daylight_factorB

Daylight Factor (%) per point under the CIE Standard Overcast Sky (gensky -c).

DF = E_indoor / E_outdoor * 100, with E_outdoor traced from a sky-only exterior reference. scene_sets: the building scene as a single 3-channel list of .rad paths (materials + geometry); the overcast sky is added internally. points: inline rows or a .pts path, OR sensor_set='name'. Returns df_per_point + df_avg/df_min/uniformity + e_outdoor, or the command plan when not run.

sensorsA

Manage named, persistent daylight sensor sets (reused across annual_daylight / daylight_factor / daylight_savings via sensor_set='name').

action: 'create' | 'list' | 'get' | 'delete'. create: name + (points=[[x,y,z,dx,dy,dz],...] OR grid={interior:[xmin,xmax,ymin,ymax], floor_z, workplane_h?, max_spacing?}); overwrite=True to replace an existing set. list: all saved sets (name, path, count, source). get: name -> the set's points + .pts path. delete: name -> remove the set.

daysim_statusA

Report Daysim availability (ds_shortterm + epw2wea) via HCL_DAYSIM_BIN or PATH.

Returns {available, bin_dir, version, found, missing}. No subprocess run except a best-effort version probe. Daysim is built from source locally (never bundled); use build_daysim if missing.

build_daysimA

Build Daysim (ds_shortterm + epw2wea) from source: clone master + headless arm64 CMake.

run=True executes if git+cmake are present; otherwise returns the ordered command plan + a reason. On success, bin_dir is the build/bin directory — set it as HCL_DAYSIM_BIN. Daysim is NOT bundled (NRC/Fraunhofer ISE source-available EULA); this clones+builds on your machine.

generate_subhourly_weaA

EPW -> sub-hourly broadband .wea via Daysim (epw2wea -> .hea -> ds_shortterm).

timestep_min default 6 (0.1 h) satisfies the nvRD step guard. Site location defaults to the EPW's own LOCATION line (converted to the DAYSIM convention), so normally you only pass the epw + work_dir. Pass explicit latitude/longitude/time_zone/site_elevation only to override — and only in DAYSIM convention: WEST-positive longitude, time_zone in DEGREES (= -15 × UTC offset); do NOT pass raw EPW East-positive coordinates. Runs Daysim if present, else returns the command plan + the written .hea so you can build Daysim and run it yourself.

reconstruct_spectrumA

Reconstruct a 401-value 380-780 nm @1 nm per-nm spectrum from sky+sun channel sets (spec §5.2).

method: 'faithful' (flat §9.3a step-expansion + neutral sun -> reproduces the legacy 2.0 method) or 'reference' (reference-SPD-shaped sky + air-mass colored direct sun; re-integrates to the channel bin totals). sun_spectral: 'colored' (air-mass solar SPD by solar_zenith) | 'neutral' (flat). dseries_sky=True reconstructs a per-timestep CIE D-series sky from sky_cct. sun_spd: optional 401-value physical sun reference that overrides the air-mass template. Returns the spectrum + the flat-vs-reference and neutral-vs-colored-sun divergence (always surfaced).

annual_nvrdA

Annual light-driven alertness (nvRD R_D) straight from weather (spec §5.1). LONG-RUNNING.

EPW -> Daysim sub-hourly .wea -> colored 2-phase DDS (sky & sun separate) -> per-timestep dual reconstruction (faithful flat + neutral sun; enhanced reference sky + air-mass colored sun) -> nvRD twice -> {faithful:{R_D,RD_cum}, enhanced:{R_D,RD_cum}, divergence, RD_series_divergence}. R_D is RELATIVE only. SINGLE reference point+view per run. reconstruction={both|faithful|enhanced} (default both). timestep_min default 6 (0.1 h). run=False emits the full Daysim+Radiance command plan — but channel_scenes and points are required for BOTH the live and emit paths (the plan is built from the actual per-channel scene transport, not from point_xyz/view_vec alone). points: inline [x,y,z,dx,dy,dz] rows OR a .pts path (a list is materialized to a .pts under work_dir, same contract as run_annual). physical_sky (opt-in): shape the enhanced reconstruction with the physical EPW-derived per-timestep sky/sun spectra instead of templates; default off. engine: spectrl2 (default) | smarts (requires SMARTSPATH); only used when physical_sky=True.

Site location is read from the EPW itself (converted to DAYSIM convention by the Daysim adapter); the tool takes no caller-supplied coordinates, so wrong-convention coordinates cannot silently corrupt the solar geometry.

recommend_fixturesC

First-principles HCL fixture sizing: lumen-method visual flux reconciled with a CIE S 026 mel-DER circadian solve. Returns flux, count, layout, CCT band, energy, and explicit caveats. distribution: direct|direct_indirect|indirect. Deterministic - always runs. See operating-guide.md workflow F.

atmosphere_from_epwB

Derived atmospheric state (AOD, PWV, ozone, pressure, albedo, aerosol_g + provenance).

Opt-in refinements (defaults reproduce prior output): ozone_mode='climatology' computes ozone from the EPW LOCATION lat/lon + date (van Heuklon 1979); aerosol_g overrides the 0.65 asymmetry; aod_anchor_nm converts a declared-wavelength AOD (e.g. 550) to tau500 via the Angstrom exponent.

spectral_sky_from_epwA

Physical spectral sky (1nm direct + sky-diffuse) reconstructed from an EPW hour.

Returns the canonical record as a dict. If surface_tilt_deg is given, also returns the spectral ground-glow term for that receiver tilt. spectral_albedo (len 401, 380-780nm @1nm) overrides the default gray albedo — pass import_geometry(...)["ground_albedo"] to couple scene ground reflectance to the sky ground-glow term. engine: spectrl2 (default) | smarts (requires SMARTSPATH).

Opt-in refinements (defaults reproduce prior output): ozone_mode='climatology' computes ozone from the EPW LOCATION lat/lon + date (van Heuklon 1979); aerosol_g overrides the 0.65 asymmetry; aod_anchor_nm converts a declared-wavelength AOD (e.g. 550) to tau500 via the Angstrom exponent. smarts_aerosol (engine="smarts" only): None/"rural" (default) or "user" to make the Ångström exponent + asymmetry factor settable via the SMARTS Card 8 USER aerosol model. cloud_variant: which SEDES1 cloud CCM to apply to the sky-diffuse spectrum — 'reanchored' (default, byte-identical to omitting this arg) | 'verbatim' (faithful Fig.11 CCM) | 'seed' (legacy eyeballed 9-anchor seed) | 'local' (your own locally-fitted CCM, requires ccm_coeffs). ccm_coeffs: path to a fitted CCM CSV (from sedes1_fit) — required when cloud_variant='local'.

spectral_epwA

Emit spectral-sky artifacts from an EPW over the year (or hours). LONG-RUNNING for a full year.

forms ⊆ {spd_set, band_matrix, spectral_wea, sidecar} (default all). Writes into work_dir and returns {files: {form: path}, n_records}. hours is a list of [month, day, hour] to subset. engine: spectrl2 (default) | smarts (requires SMARTSPATH).

Opt-in refinements (defaults reproduce prior output): ozone_mode='climatology' computes ozone from the EPW LOCATION lat/lon + date (van Heuklon 1979); aerosol_g overrides the 0.65 asymmetry; aod_anchor_nm converts a declared-wavelength AOD (e.g. 550) to tau500 via the Angstrom exponent. smarts_aerosol (engine="smarts" only): None/"rural" (default) or "user" to make the Ångström exponent + asymmetry factor settable via the SMARTS Card 8 USER aerosol model. cloud_variant: which SEDES1 cloud CCM to apply to the sky-diffuse spectrum — 'reanchored' (default, byte-identical to omitting this arg) | 'verbatim' (faithful Fig.11 CCM) | 'seed' (legacy eyeballed 9-anchor seed) | 'local' (your own locally-fitted CCM, requires ccm_coeffs). ccm_coeffs: path to a fitted CCM CSV (from sedes1_fit) — required when cloud_variant='local'.

spectral_sky_nativeA

Native Radiance 6.x spectral sky from an EPW via gensdaymtx (20-band W/sr/m² matrix).

mode: all | sun (-d) | sky (-s). Degrades to emitting the gensdaymtx + rcomb command plan when Radiance 6.x isn't installed. The melanopic collapse is rcomb -c M.

timeout caps the gensdaymtx subprocess in seconds (default None = no cap). gensdaymtx ALWAYS processes every EPW hour. A full 8760-hour year at mf=1 is fast (~12 s on Radiance 6.1a), but cost grows steeply with the Reinhart subdivision mf (minutes at mf>=4); on expiry the tool returns {ok: False, timed_out: True} rather than raising. Trim the EPW, or raise mf only as needed.

save_briefA

Persist (shallow-merge) a study brief to //brief.json. Call after each phase.

load_briefA

Load a study brief (empty skeleton if none). Call at journey start to resume where you left off.

build_reportC

Render a study brief to //report.{md,html}: goal recap, fixture spec, target-vs-achieved table with pass/fail, circadian↔glare cross-check, compliance. Always runs.

workplane_gridA

EN 12464-1 working-plane illuminance grid from an OBJ room.

Interior extent via inner-surface detection (bbox of inward-facing vertical wall faces), plane at floor-top + workplane_h, max spacing p=0.2*5^log10(d) with d=the larger dimension of the calculation area (the interior inset by border_offset, per EN 12464-1 -- not the raw interior extent), cell-centre points. Returns points [x,y,z,0,0,1] + a methodology breakdown; writes a .pts (write_pts=None to skip). material_map OR sidecar is required (to identify floor & walls). clip_to_footprint (default True) drops lattice cells outside the floor slab for non-rectangular rooms (ignored when interior_extent is supplied explicitly); footprint_border insets the kept region from the footprint edges.

observer_pointsA

Workstation eye-point observers from an OBJ room.

Auto-detects seat objects (seat_pattern) paired to screen objects (screen_pattern) by trailing suffix: eye = seat centroid at floor-top+eye_height, gaze = eye->screen centroid (dz=0). Fallback when no screen: direction_fallback in {window, azimuth, sweep}. No seats: position_fallback. Pass workstations=[{eye:[x,y], target:[x,y]|azimuth}] to bypass detection. Returns observers + glare_views (DGP fisheye) + a .pts. material_map OR sidecar required. clip_to_footprint (default True) does NOT move observers (they are furniture-anchored) — it only reports, via a warning, any observer whose eye position falls outside the floor slab.

photosensorsA

Daylight-dimming photosensors from an OBJ room (methodology.md §3).

Locates the dominant glazed facade, builds sidelighting zones from the window head height (zone_rule='head_height' with depth_factors like [1,2], or 'ies_2.5'), and places one horizontal sensor per zone at sensor_fraction of the zone depth, centred on the facade and clipped to the floor. mount='workplane' (z=floor+workplane_h, up) or 'ceiling' (down). Returns points [x,y,z,dx,dy,dz] + a per-zone methodology; writes a .pts. material_map OR sidecar required (to identify floor & glazing).

preview_sceneA

matplotlib PNG preview of a room with sensor overlays (plan + 3D).

render: 'grid' (grid, plan+3d), 'observers' (plan), 'observers_3d' (3d), or 'all' (all layers, plan+3d). Point layers are given as .pts paths OR inline [x,y,z,dx,dy,dz] rows in the post-north frame; layers left None are simply omitted. Diagnostic overlays only — not a photometric render. material_map OR sidecar required.

quality_presetsA

Ambient-quality presets: pick the accuracy/runtime trade-off up front, by name.

Radiance's ambient parameters govern the indirect (interreflected) solve, which dominates both runtime and the accuracy of every climate-based metric. Passing no rad_params means inheriting a preview-grade default by not choosing — which on a validated annual run returned sDA 77.78% where a converged solve returned 100.00% on identical geometry.

Levels, cheapest first: low -ab 0 : geometry checks and direct-sun questions only. NO interreflection. medium -ab 2 : draft studies and design comparison. Preview-grade convergence. high -ab 3 : reportable results — DA/sDA/UDI, compliance. Use this to publish. extra_high -ab 5 : indirect-dominated scenes (light shelves, atria) and validation.

Call with no argument for the full table including each level's caveat; call with a level to get just that one. Pass the level to a simulation tool as quality=, or its rad_params string directly if you want to tune from it.

get_referenceB

Look up HCL reference content. topic: bins | coefficients | caveats | overview.

list_presetsA

List available illuminant presets (CIE standards + illustrative LED models), or fetch one by name.

Names: D65, D50, A, FL1..FL12, and the illustrative LED models LED_3000K/4000K/5000K/BLUEPUMP/VIOLETPUMP (flagged illustrative, not measured - see spec 5.7). Returns SPD + metadata when a name is given.

import_weatherA

Ingest a .wea (DNI/DHI per timestamp) and/or decompose an analysis period into HOY + wea line numbers.

Returns wea_summary (record count, first/last timestamp, DNI/DHI ranges) rather than the full per-hour arrays — those reach up to 8760 rows and overflow the response budget. Use period + subset_out to get the rows you actually need (HOY/wea_lines in decomposed, the subset .wea on disk).

run_validationB

Run the built-in correctness self-test (weight sums, alpha-opic guards).

Prompts

Interactive templates invoked by user choice

NameDescription
spd_to_circadianGuide: turn an SPD into circadian metrics + compliance.
hcl_grid_studyGuide: set up a point-in-time grid HCL analysis.
fisheye_eye_analysisGuide: fisheye/FOV eye-level circadian analysis.
annual_circadian_doseGuide: annual circadian dose workflow.
explain_conceptGuide: explain an HCL metric/method/component, grounded in the reference resources.
electric_lighting_designGuide: a full electric + daylight HCL design pass with savings and EN 12464-1 interpretation.
annual_alertnessGuide: annual light-driven alertness (nvRD R_D) from weather, interpreted RELATIVELY.
hcl_studioGuide: the full start-to-finish HCL artificial-lighting journey — goal → fixture design → simulate → visualize/analyze — with a resumable study brief. The front door to a complete study.
import_obj_roomGuide: import a Wavefront .obj/CAD room into a per-channel Radiance scene, then run an HCL study.
spectral_sky_from_epwGuide: reconstruct a physical spectral sky from an EPW hour and read its circadian metrics.
place_sensorsGuide: produce EN 12464-1 grid + workstation observer points from an imported OBJ room.
annual_daylight_studyGuide: annual climate-based (photopic) daylight metrics — DA/cDA/UDI/sDA/ASE + Daylight Factor + multi-point daylight-linked energy savings, over named persistent sensor sets.
visualize_sceneGuide: render matplotlib PNG previews of a room with its sensor points.

Resources

Contextual data attached and managed by the client

NameDescription
reference-coefficientsVerified photopic/melanopic/neuropic coefficient vectors (3- and 9-channel).
reference-binsv3.0 wavelength bin definitions (3- and 9-channel).
reference-iesIESNA LM-63 data-line layout, photometric/units types, and derived metrics.
reference-lighting-controlsEnergyPlus §7.3.5 daylight-responsive lighting-control equations.
reference-daysimDaysim adapter build-from-source steps, ds_shortterm/epw2wea I/O, and credits.
reference-nvrd-bridgeThe annual->nvRD bridge data flow and honesty caveats (spec §5.1, §5.3).
reference-geometryThe import_geometry contract: material_map shape (+ surface library), the obj2rad Material/Group qualifier rule, units/axis/north, per-channel assembly, run-or-emit, and the v2/v3 conveniences (dual-height sensors, ground-albedo bridge, context-shading, drop-in electric_lights, manifest sidecar+header).
compliance-en-12464-1EN 12464-1:2021 maintained-illuminance/UGR/Uo/Ra task table + relationships.
reference-caveatsCorrectness-critical port caveats: float-division fix, channel ordering, image-vs-grid b3.
reference-glossaryDefinitions: mel-EDI, EML, mel-DER, CCT/Duv, alpha-opic, photopic/melanopic/neuropic.
indexOne-read catalog of every resource + valid template argument values.

TDQS

B3/5.0

Scored across 51 tools

Disambiguation1/5

There are at least four exact duplicate pairs (validate/run_validation, presets/list_presets, reference/get_reference, weather/import_weather), and many simulation/sensor tools overlap heavily (run_annual vs annual_daylight vs lm83_daylight vs annual_nvrd; run_grid vs daylight_factor). An agent cannot reliably distinguish which tool to call.

Naming Consistency2/5

Most names are readable snake_case, but the set mixes verb_noun (run_grid, import_geometry), noun_verb (glass_transmissivity, workplane_grid), and bare-noun tools (sensors, presets, reference, weather). The duplicate pairs use different conventions for the same function, so no predictable pattern emerges.

Tool Count1/5

51 tools is far beyond the calibration threshold for a well-scoped server, and many are near-duplicates or aliases that inflate the surface without adding capability. This is an extreme mismatch between the number of tools and what a coherent HCL server needs.

Completeness4/5

The domain surface is genuinely broad: geometry import/health/sensors, sky/weather spectral reconstruction, annual/daylight/glare/circadian simulations, compliance, controls, and reporting are all present. Minor gaps exist (e.g. non-conformant LM-83 method, unsupported UL 24480, no Radiance install path), but agents can work around them.

Maintenance

ActivityMaintained
ResponsivenessNo issues