luic-calculator-core
v1.2.5
Published
Core math and configs for the LUIC project
Downloads
318
Readme
LUIC Calculator Core
The Land Use Impact Calculator (LUIC) Core is the mathematical engine for the Land Use Impact Calculator. It takes an array of Scenario objects and produces structured outputs for energy use, GHG emissions, infrastructure costs, and revenue — either as a serializable workbook blueprint or as raw calculated values.
It is designed as a decoupled, framework-agnostic TypeScript module with no dependency on any UI framework.
Three ways to use this library
| Use case | When to use it | Entry point |
|---|---|---|
| 1. Populate a UI | Fill dropdowns, menus, defaults | Domain.* helpers |
| 2. Live calculations | Drive reactive UI math | Calculator.* functions |
| 3. Generate a workbook | Produce a report blueprint | Generator.generateWorkbook() |
Installation
npm install luic-calculator-coreImport styles
Namespace imports (recommended)
import { Generator, Domain, Calculator, Themes, i18n } from 'luic-calculator-core';Sub-path imports (optimal tree-shaking)
import { generateWorkbook } from 'luic-calculator-core/generator';
import { getProvinces } from 'luic-calculator-core/domain';
import { calcBuildingEnergyUse } from 'luic-calculator-core/calculator';
import { en, fr } from 'luic-calculator-core/i18n';
import { defaultTheme } from 'luic-calculator-core/themes';Flat named imports (backward-compatible)
import { generateWorkbook, getProvinces, calcBuildingEnergyUse } from 'luic-calculator-core';Use Case 1 — Populate a UI
Use Domain.* helpers to populate dropdowns, default values, and form fields. These are thin wrappers around the internal config objects — no calculation is performed.
import { Domain } from 'luic-calculator-core';
// Populate a province dropdown
const provinces = Domain.getProvinces();
// → [{ id: 'AB', name: 'appConfig.regions.provinces.AB' }, ...]
// Populate a neighbourhood-type picker
const neighbourhoods = Domain.getNeighbourhoodsAsArray();
// Load default sector values when a user selects a neighbourhood type
const defaults = Domain.getNeighbourhoodDefaults('urbanInfillV1');
// Populate an energy source selector for the buildings sector
const buildingEnergySources = Domain.getEnergySourcesForSector('buildings', 'BC');
// Get every configured reference with translated labels
const referencesEn = Domain.getAllReferences('en');
const referencesFr = Domain.getAllReferences('fr');
// Populate building type and energy code dropdowns
const homeTypes = Domain.getHomeTypes();
const energyCodes = Domain.getBuildingEnergyCodes();
// Get the year range for a timeline slider
const { startYear, endYear, getYearsArray } = Domain.getAppConfig();Note on i18n keys: All
.nameand.descriptionfields in domain objects are raw i18n key strings (e.g."appConfig.buildings.homeTypes.single"), not translated text. Pass them through your ownt()before rendering.Domain.getAllReferences('en' | 'fr')resolves reference labels using the built-in dictionaries while preserving their optional URLs:import { i18n } from 'luic-calculator-core'; // or use your own translation source const t = (key: string) => i18n.en[key] ?? key; const label = t(homeTypes[0].name); // → 'Single Detached'
Use Case 2 — Live calculations
Use Calculator.* functions to compute values reactively as users adjust inputs. All functions are pure (no side effects).
import { Calculator } from 'luic-calculator-core';
// Annual building energy use (kJ/yr)
const energyKJ = Calculator.calcBuildingEnergyUse(
qty, // number of dwellings
'single', // home type id
'passiveHouse' // building energy code id
);
// GHG emissions for a list of energy sources
const ghgs = Calculator.computeGhGsFromSourcesList(
'BC', // province id (affects grid EFs)
scenario.buildings.single.energySources,
2024, // reference year
'abs', // 'abs' = absolute values; any other = percentages
0 // baseline energy (only used in percentage mode)
);
// → { CO2: 1.2, CH4: 0.03, N2O: 0.001, total: 1.231 }
// → or [ { CO2, CH4, N2O, total }, ... ] for time-varying sources (e.g. grid)
// Scenario-level aggregates
const totalEnergyGJ = Calculator.sumEnergyForScenarioGJ(scenario);
const totalEmissions = Calculator.sumEmissionsForScenario(scenario);
const capCosts = Calculator.sumCostsForObj(scenario, 'services', 'capCost');
// Infrastructure and service costs
const infCap = Calculator.calcInfraCapCost(capCostIntensity, length_m);
const svcMait = Calculator.calcServiceMaintCost(maintCostIntensity, qty);
// Transportation
const totalVKT = Calculator.calcTotalVKT(vktPerDwelling, totalHomes);
const transEnergy = Calculator.computeTransportEnergyFromSourcesList(
sourcesList, 'puv', totalVKT
);Use Case 3 — Generate a workbook
Use Generator.generateWorkbook() to produce a WorkbookSpec — a fully serializable JSON blueprint describing every sheet, row, cell, formula, and chart. Hand it off to an Excel add-in or a Python/openpyxl writer.
import { Generator, Themes } from 'luic-calculator-core';
// Generate the workbook blueprint
const spec = Generator.generateWorkbook(scenarios, {
locale: 'en', // 'en' | 'fr'
theme: Themes.sunsetTheme // optional; defaults to Themes.defaultTheme
});
// Serialize to JSON for storage or transport
const json = Generator.JsonExporter.serialize(spec); // pretty-printed
const raw = Generator.JsonExporter.serialize(spec, false); // compact
// Deserialize back to WorkbookSpec
const restored = Generator.JsonExporter.deserialize(json);Available themes
| Export | Description |
|---|---|
| Themes.defaultTheme | Balanced palette — blues, greens, amber |
| Themes.sunsetTheme | High-contrast dark theme — slate, rose, dusk purple |
Pass a theme as config.theme to generateWorkbook, or build your own WorkbookTheme object using the type definitions.
Python / openpyxl
See the examples/python_post_processing/ directory for complete scripts that consume the JSON output and write .xlsx files using openpyxl:
cd examples/python_post_processing
python3 -m venv venv && source venv/bin/activate
pip install openpyxl
python3 openpyxl_writer_i18n_en.py # English workbook
python3 openpyxl_writer_i18n_fr.py # French workbook (Français)Python / XlsxWriter
An alternative writer using XlsxWriter is also available. It produces identical output but uses the XlsxWriter engine instead of openpyxl.
Note: XlsxWriter is write-only — it cannot read or modify existing
.xlsxfiles.
cd examples/python_post_processing
python3 -m venv venv && source venv/bin/activate
pip install xlsxwriter
python3 xlsxwriter_writer_i18n.py en # English workbook
python3 xlsxwriter_writer_i18n.py fr # French workbook (Français)Both scripts expect tests/test-output.json to exist (generated by npm run test:scenario) and write the result to output_i18n_en.xlsx in the same directory. Node.js must be available on PATH so the scripts can load the i18n translation file at runtime.
TypeScript types
Key types exported from the root entry point:
| Type | Description |
|---|---|
| Scenario | Root scenario object passed to generateWorkbook |
| WorkbookSpec | Output blueprint of generateWorkbook |
| GeneratorConfig | Config object for generateWorkbook (locale, theme) |
| WorkbookTheme | Full theme definition |
| EnergySource | Energy source config object |
| NeighbourhoodType | Neighbourhood type with defaults and references |
import type { Scenario, WorkbookSpec, GeneratorConfig } from 'luic-calculator-core';For GitHub Contributors
Prerequisites
- Node.js 20+
- npm (standard)
- Python 3.10+ (optional, for Excel generation examples)
Setup
git clone https://github.com/your-org/luic-calculator-core.git
cd luic-calculator-core
npm installDevelopment commands
npm run build # compile TypeScript → dist/
npm run test # run unit tests (Vitest)
npm run test:scenario # run full simulation, output → tests/test-output.json
npm run test:e2e # Python end-to-end testProject structure
src/
index.ts ← public API (re-exports everything)
api/
domain.ts ← Domain namespace barrel
calculator.ts ← Calculator namespace barrel
generator.ts ← Generator namespace barrel
i18n.ts ← i18n namespace barrel
config/
appConfig.ts ← year range, general constants
core/
calculatorUtils.ts ← all calculation functions
genericUtils.ts ← array/object utilities
domain/ ← buildings, services, energy sources, etc.
i18n/ ← en.ts / fr.ts translation dictionaries
generator/
WorkbookGenerator.ts ← generateWorkbook() entry point
builders/ ← per-sheet builder classes
FormulaBuilder.ts ← fluent Excel formula builder
theme/ ← defaultTheme, sunsetTheme
types/ ← TypeScript interfaces
utils/ ← formatting, cell addressing, reactivity
writers/
JsonExporter.ts ← serialize / deserialize WorkbookSpecLicense
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
3. **Run Unit Tests**:
```bash
npm run testGenerate Test Scenarios: To run a full simulation using sample data:
npm run test:scenarioOutputs are saved to
tests/test-output.json.To generate a comparative simulation testing three scenarios (without parking/pathways, with zero quantities, and with actual quantities/costs):
npm run test:scenario-parkingAndPathwaysOutputs are saved to
tests/test-output-parking-pathways.json.
Python Post-Processing (Excel Generation)
The core engine outputs raw data. To see how to transform this data into formatted Excel workbooks using openpyxl, check the examples/ directory.
cd examples/python_post_processing
python3 -m venv venv
source venv/bin/activate
pip install openpyxl
python3 openpyxl_writer.py / python3 openpyxl_writer_i18n_en.py / python3 openpyxl_writer_i18n_fr.py / python3 openpyxl_writer_parkingAndPathways_en.py
# openpyxl_writer_i18n_en.py — generates the workbook with labels translated to English
# openpyxl_writer_i18n_fr.py — generates the workbook with labels translated to French (Français)
# openpyxl_writer_parkingAndPathways_en.py — generates the comparative parking & pathways workbook (translated to English) from tests/test-output-parking-pathways.jsonLicense
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
