Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
/zero_engine
opencode.Containerfile
compose.yaml

/site
.venv
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,19 @@
# LUX ENERGY TWIN DOCUMENTATION

Source of [docs.lux.energy](https://docs.lux.energy)
This repository contains the code for the user and the technical documentation for LUX Energy Twin, or LUX for short.

For those just interested in reading the docs, they can be easily accessed at [docs.lux.energy](https://docs.lux.energy).

The rest of this file is for those interested in contributing to the docs.

The documentation guidelines can be found in the file: `documentation_guidelines`.

The documentation is automatically deployed to the LUX website so that it is always up to date with the status of this repository.

When developping the results can be viewed locally by running the following command:

```
podman run --volume .:/app docker.io/javanile/mkdocs:latest sh -c "pip3 install pymdown-extensions && mkdocs build"
```

This produces html files in the folder `site`, which can be opened in your browser of choice.
40 changes: 40 additions & 0 deletions documentation_guidelines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Documentation Guidelines

This document is aimed to help you create documentation pages that match the structure and style of our docs. \
The documentation is in markdown files \( \.md \), the basic syntax of which can be found [here](https://www.markdownguide.org/basic-syntax/)

## What should be documented?

Any sufficiently important Agent, Class or Function in the LUX model. The scope of the LUX model is: the engine, loader, interface, resultsUI and projectTemplate.

Sufficiently important is ofcourse a subjective statement, but as a rule of thumb:

> If a piece of code is of vital importance to the workings of the model, or contains assumptions that have significant impact on the model results it should be documented.

## Structure of a documentation page

All documentation pages should try to follow the same structure. The page should contain at least the following information:

* A (short) introduction on the piece of code. How does it fit into the model's architecture. What function does it fulfil in the model.
* If it is a class or agent, what are the most important parameters & variables? For each of those describe why it is of importance. You may also want to describe where the choice of parameter is determined or where it is used by the class.
* If it is a class or agent, what are the most important functions & methods? For each of those describe why it is of importance.

## Styling

* Every page should start with a title, which is added by starting a line with a \# (Level 1 heading).
* A page may contains paragraphs, which are added by lines starting with \#\# (Level 2 heading).
* Small code snippits that fit inline and names of variables, classes, functions, etc. must be displayed between backticks \( \` \) \
For example: `p_timeVariables.updateTimeVariables(v_timeStepsElapsed, p_timeParameters);`
* Larger code snippits that span multiple lines must be displayed as fenced code blocks between three backticks \( \`\`\` \) \
You can also specify the language of the code after the first three backticks, e.g. \`\`\`java \
The result looks like this:
```java
for (GridConnection gc : c_gridConnections) {
gc.f_calculateEnergyBalance(p_timeVariables, v_isRapidRun);
}
```
* Functions discriptions are code snippits, hence displayed between backticks. \
Functions may list all their arguments, some of their arguments, or none of their arguments. \
Arguments that are omitted are replaced with three dots \( \.\.\. \) \
Usually from the arguments both the type and name is mentioned, the variable name is only mentioned in larger code snippits where it is relevant or when there is ambiguity , so not in function descriptions. \
For example in `J_RapidRunData`: `addTimeStep( J_FlowsMap fm_currentBalanceFlows_kW, J_FlowsMap fm_currentConsumptionFlows_kW, ... , J_TimeVariables timeVariables)`
22 changes: 11 additions & 11 deletions site/engine/consistency_checks/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -138,31 +138,31 @@
<div class="section" itemprop="articleBody">

<h1 id="consistency-checks">Consistency Checks</h1>
<p>The LUX engine applies several consistency checks to ensure a correct and leak-free energy balance.</p>
<p>The LUX engine applies several consistency checks to ensure a correct model.</p>
<h2 id="configuration-check">Configuration Check</h2>
<p>The configuration check validates the model setup before simulation. It is implemented as <code>f_checkConfiguration()</code> methods on the <a href="../energy_model/">EnergyModel</a> and <a href="../grid_connections/">GridConnections</a>.</p>
<p>The EnergyModel's <code>f_checkConfiguration()</code> iterates over all GridConnections and calls their individual check.</p>
<p>The GridConnection's <code>f_checkConfiguration()</code> checks:</p>
<p>The GridConnection's <code>f_checkConfiguration()</code> checks for:</p>
<ul>
<li><strong>Flex assets without an EMS</strong>: If a GridConnection has flexible assets (<code>c_flexAssets</code>) but no <code>I_EnergyManagement</code> (EMS) is configured, a <code>RuntimeException</code> is thrown: <code>"GC: {id} has flex assets, without an EMS"</code>.</li>
<li><strong>EMS-level validation</strong>: If an EMS is present, the check is delegated to the EMS's own <code>checkConfiguration()</code> method. Each EMS implementation validates that the set of flex assets matches its expected management types.</li>
<li><strong>Flex assets without an EMS</strong>: If a GridConnection has flexible assets (<code>c_flexAssets</code>) but no <code>I_EnergyManagement</code> (EMS) is configured, a <code>RuntimeException</code> is thrown.</li>
<li><strong>EMS-level validation</strong>: If an EMS is present, the check is delegated to the EMS's own <code>checkConfiguration()</code> method. Each EMS implementation validates that the set of flex assets matches its expected types.</li>
</ul>
<p>This ensures that every agent with flexible equipment has a valid control system assigned before the simulation runs.</p>
<p>This ensures that every agent with flexible assets has a valid control system assigned before the simulation runs.</p>
<h2 id="energy-balance-check">Energy Balance Check</h2>
<p>The energy balance check (implemented as <code>f_performEnergyBalanceCheck()</code> on the EnergyModel) verifies the law of conservation of energy: energy cannot be created or destroyed in the model.</p>
<p>Energy can only enter or leave the model through these paths:</p>
<ul>
<li><strong>Import</strong> of electricity, gas, hydrogen, and petroleum fuel.</li>
<li><strong>Export</strong> of electricity, gas, and hydrogen.</li>
<li><strong>Primary production</strong>: Energy harvested from the environment (e.g. wind, solar irradiation, ambient heat absorbed by buildings). Tracked as <code>energyProduction_kW</code>.</li>
<li><strong>Final consumption</strong>: Energy that leaves the system as losses (dissipated heat, conversion losses, consumption profiles). Tracked as <code>energyConsumption_kW</code>.</li>
<li><strong>Import</strong> of energy carriers.</li>
<li><strong>Export</strong> of energy carriers.</li>
<li><strong>Primary production</strong>: Energy harvested from the environment (e.g. wind, solar irradiation, ambient heat absorbed by buildings).</li>
<li><strong>Final consumption</strong>: Energy that leaves the system as losses (dissipated heat, conversion losses, consumption profiles).</li>
</ul>
<p>The balance equation is:</p>
<pre class="highlight"><code class="language-math">Production - Export = Consumption - Import = SelfConsumption</code></pre>
<pre class="highlight"><code class="language-math">Production - Export = Consumption - Import</code></pre>
<p>In code, the check computes:</p>
<pre class="highlight"><code class="language-java">double energyBalanceCheck_MWh = totalImport_MWh + totalProduction_MWh
- (totalExport_MWh + totalConsumption_MWh + totalDeltaStoredEnergy_MWh);</code></pre>
<p>This value must be zero. If it exceeds a tolerance of 1e-6 MWh, a warning is logged. The check also accounts for changes in stored energy (battery charge state, thermal storage in buildings) to prevent false positives from energy buffers that are not empty at the end of the simulation.</p>
<p>This value must be zero. If it exceeds a tolerance of 1e-6 MWh, a warning is logged. The check also accounts for changes in stored energy (battery charge state, thermal storage in buildings) to prevent false positives from energy buffers that the same at the end of the simulation compared to the start.</p>

</div>
</div><footer>
Expand Down
12 changes: 3 additions & 9 deletions site/engine/data_structures/accumulator_maps/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
<div class="section" itemprop="articleBody">

<h1 id="accumulator-maps">Accumulator Maps</h1>
<p>Accumulator Maps store a set of <a href="../accumulators/">accumulators</a> keyed by an enum type. The implementation is class <code>J_AccumulatorMap&lt;E extends Enum&lt;E&gt;&gt;</code>.</p>
<p>Accumulator Maps store a set of <a href="../accumulators/">accumulators</a> keyed by an enum type. The implementation is class <code>J_AccumulatorMap&lt;E extends Enum&lt;E&gt;&gt;</code>. During the simulation the results are stored in these accumulators. Agents loop over their energy carriers, asset flow categories or other option list and the individual accumulators are accessed and updated.</p>
<p>The constructor takes one argument:</p>
<ul>
<li><strong>Class\&lt;E&gt; enumClass</strong>: The enum type that defines the possible keys.</li>
Expand All @@ -149,14 +149,8 @@ <h1 id="accumulator-maps">Accumulator Maps</h1>
<li><strong><code>reset()</code></strong>: Resets all accumulators in the map.</li>
<li><strong><code>clear()</code></strong>: Removes all accumulators from the map.</li>
<li><strong><code>keySet()</code></strong>: Returns the set of keys that have accumulators.</li>
</ul>
<p>Just like the accumulator, it is possible to add or subtract entire accumulator maps (the keys must match).</p>
<p>Convenience methods for aggregating over all keys:</p>
<ul>
<li><strong><code>totalIntegral_kWh()</code></strong>: Sum of <code>getIntegral_kWh()</code> across all accumulators.</li>
<li><strong><code>totalIntegralPos_kWh()</code></strong>: Sum of <code>getIntegralPos_kWh()</code> across all accumulators.</li>
<li><strong><code>totalIntegralNeg_kWh()</code></strong>: Sum of <code>getIntegralNeg_kWh()</code> across all accumulators.</li>
<li><strong><code>totalIntegral_MWh()</code> / <code>totalIntegralPos_MWh()</code> / <code>totalIntegralNeg_MWh()</code></strong>: MWh variants of the above.</li>
<li><strong><code>add(J_AccumulatorMap&lt;E&gt; accumulatorMap)</code></strong>: adds the accumulators of another accumulator map to the accumulators of this map and returns this object.</li>
<li><strong><code>subtract(J_AccumulatorMap&lt;E&gt; accumulatorMap)</code></strong>: subtracts the accumulators of another accumulator map to the accumulators of this map and returns this object.</li>
</ul>
<p>Accumulator maps can be converted to <a href="../dataset_maps/">DataSetMaps</a> via <code>getDataSetMap(startTime_h)</code> or <code>getDataSetMap(startTime_h, dataSetSignalResolution_h)</code>. The latter allows downsampling to a coarser signal resolution, given that it is a multiple of the accumulator's resolution.</p>

Expand Down
2 changes: 1 addition & 1 deletion site/engine/data_structures/dataset_maps/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@
<div class="section" itemprop="articleBody">

<h1 id="dataset-maps">DataSet Maps</h1>
<p>DataSet Maps store a set of <a href="https://anylogic.help/anylogic/analysis/data-set.html">AnyLogic DataSets</a> (XY charts) keyed by an enum type. The implementation is class <code>J_DataSetMap&lt;E extends Enum&lt;E&gt;&gt;</code>.</p>
<p>DataSet Maps store a set of <a href="https://anylogic.help/anylogic/analysis/data-set.html">AnyLogic DataSets</a> (2D XY data) keyed by an enum type. The implementation is class <code>J_DataSetMap&lt;E extends Enum&lt;E&gt;&gt;</code>.</p>
<p>DataSet Maps are typically created from <a href="../accumulator_maps/">accumulator maps</a> via <code>getDataSetMap(startTime_h)</code>, which converts each accumulator's time series to an AnyLogic DataSet for rendering charts and graphs.</p>
<p>The constructor accepts one argument:</p>
<ul>
Expand Down
8 changes: 4 additions & 4 deletions site/engine/data_structures/profile_pointers/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -139,21 +139,21 @@ <h1 id="profile-pointers">Profile Pointers</h1>
<p>Unlike <a href="../accumulators/">Accumulators</a> and <a href="../time_series/">Time Series</a> which store simulation <em>results</em>, profile pointers read pre-defined input profiles. The profile data is stored as a <code>double[]</code> array with a fixed timestep.</p>
<p>The constructor accepts the following arguments:</p>
<ul>
<li><strong>String name</strong>: A descriptive name for this profile (e.g. "temperature", "electricity_price").</li>
<li><strong>String name</strong>: A descriptive name for this profile (e.g. "ground_temperature", "day_ahead_electricity_price").</li>
<li><strong>double[] profile</strong>: The array of data values.</li>
<li><strong>double dataTimeStep_h</strong>: The time step between consecutive values in the profile array.</li>
<li><strong>double dataStartTime_h</strong>: The start time of the first profile entry, relative to 00:00 on January 1st of the simulation year.</li>
<li><strong>OL_ProfileUnits profileUnits</strong>: The physical unit of the profile values.</li>
</ul>
<p>Key methods:</p>
<ul>
<li><strong><code>getValue(double time_h)</code></strong>: Returns the profile value at the given simulation time. Supports profile looping: when <code>enableProfileLooping</code> is true (default), indices beyond the array length wrap around using modulo arithmetic.</li>
<li><strong><code>updateValue(double t_h)</code></strong>: Calls <code>getValue(t_h)</code> and stores the result internally.</li>
<li><strong><code>getCurrentValue()</code></strong>: Returns the most recently updated value.</li>
<li><strong><code>getValue(double time_h)</code></strong>: Returns the profile value at the given simulation time. Supports profile looping: when <code>enableProfileLooping</code> is true (default), indices beyond the array length wrap around using modular arithmetic.</li>
<li><strong><code>updateValue(double t_h)</code></strong>: Calls <code>getValue(t_h)</code> and stores the result internally.</li>
<li><strong><code>getAllValues()</code></strong>: Returns a clone of the full profile array.</li>
<li><strong><code>getDataTimeStep_h()</code></strong>: Returns the time step of the profile data.</li>
</ul>
<p>The <code>updateValue</code> / <code>getCurrentValue</code> pattern is typically used each timestep during the simulation to avoid repeated index calculations.</p>
<p>The <code>updateValue</code> / <code>getCurrentValue</code> pattern is used each timestep, called by the <a href="../../energy_model/">EnergyModel</a> for all profile pointers during the simulation to avoid repeated index calculations.</p>
<p>For forecasting over a profile, see <a href="../profile_forecasters/">profile forecasters</a>.</p>

</div>
Expand Down
2 changes: 1 addition & 1 deletion site/engine/energy_carriers/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ <h1 id="energy-carriers">Energy Carriers</h1>
<li>Iron_powder</li>
</ul>
<p>Other energycarriers can be easily added to the optionlist.
All the datastructures, such as the <a href="../data_structures/accumulators/">accumulators</a> in the rapidrundata, that store data for charts and graphs are dynamically extended to include these new energycarriers.
All the datastructures, such as the <a href="../data_structures/accumulators/">accumulators</a> in maps in the rapidrundata, that store data for charts and graphs are dynamically extended to include these new energycarriers.
The engine keeps track of which energycarriers are used in the model. This is done through the EnumSets activeProductionEnergyCarriers and activeConsumptionEnergyCarriers in the energy assets.</p>

</div>
Expand Down
11 changes: 3 additions & 8 deletions site/engine/energy_coops/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,9 @@ <h1 id="energy-cooperatives">Energy Cooperatives</h1>
<p>The <code>EnergyCoop</code> agent implements <code>I_EnergyData</code>, exposing rapid-run and live data for results visualization. It extends the <code>Actor</code> class.</p>
<p><strong>Key fields:</strong></p>
<ul>
<li><strong><code>c_memberGridConnections</code> / <code>c_customerGridConnections</code></strong>: GridConnections belonging to the cooperative as members (producers) or customers (consumers).</li>
<li><strong><code>v_energyPassedThrough_kWh</code></strong>: Total energy passed through the cooperative.</li>
<li><strong><code>v_electricityVolume_kWh</code> / <code>v_heatVolume_kWh</code> / <code>v_methaneVolume_kWh</code> / <code>v_hydrogenVolume_kWh</code></strong>: Energy volumes per carrier.</li>
</ul>
<p><strong>Key methods:</strong></p>
<ul>
<li><strong><code>f_connectToChild(Actor, OL_EnergyCarriers)</code></strong>: Adds members and customers, categorizing them by actor group.</li>
<li><strong><code>f_updateIncentives()</code></strong>: Updates the cooperative's pricing incentives for its members.</li>
<li><strong><code>c_memberGridConnections</code> / <code>c_customerGridConnections</code></strong>: GridConnections belonging to the cooperative as members (producers) or customers (consumers). In an E-Hub all gridconnections are members.</li>
<li><strong><code>f_calculateEnergyBalance</code></strong>: This function is the main part of the engine loop every timestep. It resets the energy flows, loops through the coop members and customers to aggregate the energy flows. Then it stores the results in either the live data or rapidrun data class.</li>
<li><strong><code>f_operateAggregatorEnergyManagement</code></strong>: This function is called by the energymodel after all gridconnections have operated their assets and will determine the behaviour for the aggregated assets for the next timestep. This means aggregated assets in an EnergyCoop will always have one timestep delay in their behaviour.</li>
</ul>
<p>The EnergyCoop agent allows for a centralized <a href="../energy_management_systems/">EMS</a> that takes control from individual GridConnections and manages all (or a subset of) the flexible assets from a single point. This allows members of an Energy Hub to use more of their existing connection capacities or increase their combined self-consumption.</p>
<p>An example of an Energy Cooperative model developed with LUX is the <a href="https://coco.local4local.nu/">Cooperatie Configurator</a>. Models about Energy Hubs are usually restricted in their access because of the sensitive company data.</p>
Expand Down
Loading
Loading