Skip to content

Sizing & Simulation API

Base paths:

  • /core/api/communities/{community_id}/sizing_general_parameters
  • /core/api/communities/{community_id}/sizing_meter_static_parameters
  • /core/api/communities/{community_id}/meter_dynamic_parameters
  • /core/api/communities/{community_id}/payload
  • /core/api/communities/{community_id}/sizing_simulation
  • /core/api/simulator

The Sizing module is a pre-delivery planning tool: given a community's meters, contracts, consumption and generation profiles, it runs a MILP (the rec_sizing collective-pool model) that suggests the optimal contracted power and the optimal new PV (RES) and battery capacity per CPE, together with the resulting energy flows between members. See the Glossary and the Platform Overview for where sizing fits. It is separate from the Energy Management modules described in Optimization.

A sizing run follows this order:

  1. Store the community-wide general parameters (one row per community).
  2. Store per-meter static parameters (investment costs, capacity limits) for each CPE.
  3. Make sure the community has CPEs with contracts, linked SCPU/STORAGE resources, loads and opportunity costs for the sizing period.
  4. Call build and simulate. It returns 202 immediately and the MILP runs in a Celery task.
  5. Read the results (replaced on every run).

The Simulator endpoints at the end of the page are a different feature: they build a complete demo community from a simulator export file and trigger market and settlement tasks on it.

Units and time

Energy is in kWh, power in kW, prices and tariffs in EUR (see each field). Result timestamps are returned in the platform time zone (Europe/Lisbon). Sizing steps are 15 minutes (delta_t = 0.25) or hourly (delta_t = 1).

Business validity

A sizing period cannot cross a day on which the community structure changes. The check runs inside the Celery task (not in the HTTP response); see Business Validity.

Authentication coverage

Only the general-parameters router (GET, POST, PUT on sizing_general_parameters) and the simulator router declare authentication dependencies in the code. The static-parameters, dynamic-parameters, payload and sizing-simulation routers declare no authentication or permission dependency. Always send the bearer token regardless, as described in Authentication.

Endpoint summary

Method Path Purpose
POST /core/api/communities/{community_id}/sizing_general_parameters Create (or update) the community's general sizing parameters
GET /core/api/communities/{community_id}/sizing_general_parameters Get the general parameters of a community
GET /core/api/communities/{community_id}/sizing_general_parameters/{general_params_id} Get general parameters by ID
PUT /core/api/communities/{community_id}/sizing_general_parameters/{general_params_id} Partially update general parameters
POST /core/api/communities/{community_id}/sizing_meter_static_parameters Create static sizing parameters for a meter
GET /core/api/communities/{community_id}/sizing_meter_static_parameters/{meter_id} List static parameters of a meter
PUT /core/api/communities/{community_id}/sizing_meter_static_parameters/{parameter_id} Update static parameters
POST /core/api/communities/{community_id}/meter_dynamic_parameters Upload dynamic parameters (consumption CSV)
PUT /core/api/communities/{community_id}/meter_dynamic_parameters/{meter_id} Update dynamic parameter rows of a meter
POST /core/api/communities/{community_id}/payload/build_and_simulate Build the sizing payload and run the simulation
GET /core/api/communities/{community_id}/sizing_simulation/results Get sizing simulation results
POST /core/api/simulator Create a demo community from a simulator export
POST /core/api/simulator/{community_id}/simulationtask/{task_name} Run a market/settlement/EMS task on a simulator community

General Parameters

One row of general parameters exists per community. They configure the MILP as a whole.

Field Type Description
nr_days integer Number of days to consider. Stored, but the payload builder derives the number of days from the start_date and end_date of the run (end_date - start_date + 1)
nr_clusters integer Number of representative days for clustering time series. 0 disables clustering; the value is only sent to the solver when greater than 0 and the solver ignores values larger than the number of days
l_grid number Access tariff for self-consumed energy, EUR/kWh. Expanded to a constant array over the sizing period
delta_t number Optimization step in hours: 0.25 (15 minutes) or 1 (hourly). With any value other than 0.25, the 15-minute inputs are aggregated to hourly
storage_ratio number Reference ratio between maximum storage input/output power and nominal capacity (kW/kWh) used for new storage suggestions
strict_pos_coeffs boolean If true, dynamic allocation coefficients must be strictly positive
total_share_coeffs boolean If true, meters with surplus must share all of it with consuming meters when the community has a deficit

Create or Update General Parameters

POST /core/api/communities/{community_id}/sizing_general_parameters

Creates the general parameters of a community and returns 201. The router is written as an upsert: if the community already has a row, it should update it instead of creating a second one.

Auth / permissions: any authenticated user (get_current_user); the community must exist. The router does not check community membership.

Parameter In Type Required Description
community_id path UUID Yes Community ID
community_id body UUID Yes Required by the schema (otherwise 422), but overwritten with the path value on creation
nr_days body integer Yes See table above
nr_clusters body integer Yes See table above
l_grid body number Yes EUR/kWh
delta_t body number Yes 0.25 or 1
storage_ratio body number Yes kW/kWh
strict_pos_coeffs body boolean Yes
total_share_coeffs body boolean Yes

Example

curl -X POST https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/sizing_general_parameters \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "nr_days": 30,
    "nr_clusters": 0,
    "l_grid": 0.05,
    "delta_t": 0.25,
    "storage_ratio": 1,
    "strict_pos_coeffs": true,
    "total_share_coeffs": true
  }'

Response (abridged)

{
  "id": "9b2f1c1e-6a3d-4f6e-8f55-0d9b6c1a7e42",
  "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "nr_days": 30,
  "nr_clusters": 0,
  "l_grid": 0.05,
  "delta_t": 0.25,
  "storage_ratio": 1.0,
  "strict_pos_coeffs": true,
  "total_share_coeffs": true
}

Known issue: calling POST when parameters already exist

The "update existing" branch calls crud.update_general_parameters, which does not exist in the CRUD module (the function is named update_sizing_general_parameters). As the code stands, a second POST for the same community fails with 500. Use PUT /core/api/communities/{community_id}/sizing_general_parameters/{general_params_id} to change existing parameters.

Tip

No uniqueness constraint exists on community_id in the table, so always GET first (or rely on the 404) before creating. The sizing payload builder reads the first row found for the community, and returns an error in the Celery task if none exists.

Get General Parameters of a Community

GET /core/api/communities/{community_id}/sizing_general_parameters

Returns the general parameters of the community. Use it to decide between POST and PUT.

Auth / permissions: any authenticated user (get_current_user); the community must exist.

Parameter In Type Required Description
community_id path UUID Yes Community ID

Example

curl https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/sizing_general_parameters \
  -H "Authorization: Bearer $TOKEN"

Response (abridged)

{
  "id": "9b2f1c1e-6a3d-4f6e-8f55-0d9b6c1a7e42",
  "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "nr_days": 30,
  "nr_clusters": 0,
  "l_grid": 0.05,
  "delta_t": 0.25,
  "storage_ratio": 1.0,
  "strict_pos_coeffs": true,
  "total_share_coeffs": true
}

Tip

Returns 404 with "General parameters for the specified community not found." when none were created yet, and 404 (Community with id: ... does not exist.) when the community itself is unknown.

Get General Parameters by ID

GET /core/api/communities/{community_id}/sizing_general_parameters/{general_params_id}

Returns one general-parameters row by its own ID.

Auth / permissions: any authenticated user (get_current_user); the community must exist.

Parameter In Type Required Description
community_id path UUID Yes Community ID
general_params_id path UUID Yes ID of the general-parameters row

Example

curl https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/sizing_general_parameters/9b2f1c1e-6a3d-4f6e-8f55-0d9b6c1a7e42 \
  -H "Authorization: Bearer $TOKEN"

Response (abridged)

{
  "id": "9b2f1c1e-6a3d-4f6e-8f55-0d9b6c1a7e42",
  "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "nr_days": 30,
  "nr_clusters": 0,
  "l_grid": 0.05,
  "delta_t": 0.25,
  "storage_ratio": 1.0,
  "strict_pos_coeffs": true,
  "total_share_coeffs": true
}

Tip

The lookup uses only general_params_id; it does not verify that the row belongs to the community_id in the path. Returns 404 (General parameters not found) for an unknown ID.

Update General Parameters

PUT /core/api/communities/{community_id}/sizing_general_parameters/{general_params_id}

Partially updates a general-parameters row. Only the fields present (not null) in the body are changed.

Auth / permissions: any authenticated user (get_current_user); the community must exist.

Parameter In Type Required Description
community_id path UUID Yes Community ID
general_params_id path UUID Yes ID of the general-parameters row
nr_days body integer No
nr_clusters body integer No
l_grid body number No EUR/kWh
delta_t body number No 0.25 or 1
storage_ratio body number No kW/kWh
strict_pos_coeffs body boolean No
total_share_coeffs body boolean No

Example

curl -X PUT https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/sizing_general_parameters/9b2f1c1e-6a3d-4f6e-8f55-0d9b6c1a7e42 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"delta_t": 1, "nr_clusters": 5}'

Response (abridged)

{
  "id": "9b2f1c1e-6a3d-4f6e-8f55-0d9b6c1a7e42",
  "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "nr_days": 30,
  "nr_clusters": 5,
  "l_grid": 0.05,
  "delta_t": 1.0,
  "storage_ratio": 1.0,
  "strict_pos_coeffs": true,
  "total_share_coeffs": true
}

Tip

Because null means "leave unchanged", this endpoint cannot be used to clear a value; all columns are required in the database anyway. Returns 404 for an unknown general_params_id. Setting delta_t to 1 makes the sizing run aggregate consumption (sum) and opportunity costs (average) to hourly values.

Meter Static Parameters

Static parameters hold the per-meter economic and capacity inputs of the MILP. They are read for each CPE meter that has contracts. A CPE without a row is sent to the solver with all of these values set to 0.0.

Field Type Description
l_cont number Contracted-power tariff of the meter, adjusted to one day (EUR/kW.day)
l_gic number Investment cost of new RES (PV) capacity, adjusted to one day over the panel lifespan (EUR/kW.day)
l_bic number Investment cost of new storage capacity, adjusted to one day over the battery lifespan
p_meter_max number Maximum power the meter can safely handle (kW); constrains the total contracted power
p_gn_min number Minimum new RES capacity to install at the meter (kW)
p_gn_max number Maximum new RES capacity to install at the meter (kW)
e_bn_min number Minimum storage capacity to install at the meter (kWh)
e_bn_max number Maximum storage capacity to install at the meter (kWh)

All fields are optional. The table enforces one row per (meter_id, community_id).

Create Static Parameters

POST /core/api/communities/{community_id}/sizing_meter_static_parameters

Creates the static sizing parameters of one meter.

Auth / permissions: no authentication or permission dependency is declared in the router code.

Parameter In Type Required Description
community_id path string (UUID) Yes Community ID; overwrites community_id in the body
meter_id body UUID Yes CPE meter these parameters belong to
community_id body UUID Yes Required by the schema, then replaced by the path value
l_cont, l_gic, l_bic body number No Costs, see table above
p_meter_max, p_gn_min, p_gn_max body number No kW
e_bn_min, e_bn_max body number No kWh

Example

curl -X POST https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/sizing_meter_static_parameters \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "meter_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "l_cont": 0.042753623,
    "l_gic": 0.009343915,
    "l_bic": 0.000547945,
    "p_meter_max": 41.4,
    "p_gn_min": 0,
    "p_gn_max": 30,
    "e_bn_min": 0,
    "e_bn_max": 60
  }'

Response (abridged)

{
  "meter_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "l_cont": 0.042753623,
  "l_gic": 0.009343915,
  "l_bic": 0.000547945,
  "p_meter_max": 41.4,
  "p_gn_min": 0.0,
  "p_gn_max": 30.0,
  "e_bn_min": 0.0,
  "e_bn_max": 60.0
}

Tip

The response model is the create schema, so the generated row id is not returned; fetch it with the GET below when you need to PUT. A second row for the same meter and community violates the unique index; the router wraps every error in a generic handler, so this and a non-existent meter_id both surface as 500 with the database error text in detail.

List Static Parameters of a Meter

GET /core/api/communities/{community_id}/sizing_meter_static_parameters/{meter_id}

Returns the static parameter rows of a meter (at most one in practice, because of the unique index).

Auth / permissions: no authentication or permission dependency is declared in the router code.

Parameter In Type Required Description
community_id path string Yes Community ID (not used by the lookup)
meter_id path string (UUID) Yes Meter ID

Example

curl https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/sizing_meter_static_parameters/7c9e6679-7425-40de-944b-e07fc1f90ae7 \
  -H "Authorization: Bearer $TOKEN"

Response (abridged)

[
  {
    "id": "0d6f3b52-92a4-4f0a-9a1f-6b6a5e1d2c33",
    "meter_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "l_cont": 0.042753623,
    "l_gic": 0.009343915,
    "l_bic": 0.000547945,
    "p_meter_max": 41.4,
    "p_gn_min": 0.0,
    "p_gn_max": 30.0,
    "e_bn_min": 0.0,
    "e_bn_max": 60.0
  }
]

Tip

Returns [] (not 404) when the meter has no static parameters. The lookup filters only by meter_id. An invalid UUID is rejected with an error that surfaces as 500 (see the create endpoint).

Update Static Parameters

PUT /core/api/communities/{community_id}/sizing_meter_static_parameters/{parameter_id}

Updates a static-parameters row by its own ID.

Auth / permissions: no authentication or permission dependency is declared in the router code.

Parameter In Type Required Description
community_id path string Yes Community ID (not used by the update)
parameter_id path string (UUID) Yes ID of the static-parameter row (from the GET above)
l_cont, l_gic, l_bic body number No Costs
p_meter_max, p_gn_min, p_gn_max body number No kW
e_bn_min, e_bn_max body number No kWh

Example

curl -X PUT https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/sizing_meter_static_parameters/0d6f3b52-92a4-4f0a-9a1f-6b6a5e1d2c33 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "l_cont": 0.042753623,
    "l_gic": 0.009343915,
    "l_bic": 0.000547945,
    "p_meter_max": 50,
    "p_gn_min": 0,
    "p_gn_max": 40,
    "e_bn_min": 0,
    "e_bn_max": 80
  }'

Response (abridged)

{
  "l_cont": 0.042753623,
  "l_gic": 0.009343915,
  "l_bic": 0.000547945,
  "p_meter_max": 50.0,
  "p_gn_min": 0.0,
  "p_gn_max": 40.0,
  "e_bn_min": 0.0,
  "e_bn_max": 80.0
}

Warning

This is a full replace, not a patch: every field of the schema is written, so any field omitted from the body is saved as null (treated as 0.0 by the sizing run). Always send the complete set of values.

Tip

An unknown parameter_id raises 404 (Static meter parameter not found.) inside a blanket error handler, so the client receives 500 with 404: Static meter parameter not found. in detail.

Meter Dynamic Parameters

Dynamic parameters are time-series rows per meter (datetime_timestamp, l_buy, l_sell, e_c, e_g_factor). Upload historical consumption with the CSV template Sizing energy consumed (also listed in Upload Templates).

Current usage by the sizing run

The payload builder currently takes consumption and generation from the community Loads (see Loads API) and costs from opportunity costs. The block that would read e_c from the dynamic parameters is commented out in the code, so uploaded dynamic parameters are stored but do not feed build_and_simulate. There is no GET endpoint for dynamic parameters.

Upload Dynamic Parameters

POST /core/api/communities/{community_id}/meter_dynamic_parameters

Uploads a CSV with historical consumption per meter. The file is processed asynchronously by the upload_meter_dynamic_parameters Celery task (queue file_uploads).

Auth / permissions: no authentication or permission dependency is declared in the router code.

Parameter In Type Required Description
community_id path string (UUID) Yes Community ID
file_upload body (multipart) file Yes UTF-8 CSV with columns DateTime, Contador, e_c

CSV columns:

Column Description
DateTime DD/MM/YYYY HH:MM, for example 01/05/2023 00:15
Contador Meter identifier, which must exist in the community. Rows without it would have no meter and be rejected by the database
e_c Energy consumed in the interval, kWh

Example

curl -X POST https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/meter_dynamic_parameters \
  -H "Authorization: Bearer $TOKEN" \
  -F "file_upload=@template_sizizing_e_consumed.csv"

Response (abridged)

{
  "message": "Processing started",
  "task_id": "6f5b1a52-5d1c-4c0e-9a0b-2e8a1f3d9c10"
}

Tip

Poll GET /core/api/communities/{community_id}/tasks/{task_id}?group_task=false for the outcome. On success the task result reads Successfully inserted N dynamic meter parameters. Failures inside the task (missing e_c header, bad date format, unknown meter identifier) are reported through the task state, not the HTTP response. Rows are appended; re-uploading does not replace earlier rows. An invalid community_id is intended to return 400, but because of the blanket error handler it returns 500 (Internal Server Error).

Update Dynamic Parameters of a Meter

PUT /core/api/communities/{community_id}/meter_dynamic_parameters/{meter_id}

Updates existing dynamic-parameter rows of a meter. The body is a list of objects, each identifying a row by its id.

Auth / permissions: no authentication or permission dependency is declared in the router code.

Parameter In Type Required Description
community_id path string (UUID) Yes Community ID
meter_id path string (UUID) Yes Meter ID
[].id body UUID Yes ID of the dynamic-parameter row to update
[].l_buy body number No Defaults to 0.0 when omitted
[].l_sell body number No Defaults to 0.0 when omitted
[].e_c body number No Consumption in kWh; defaults to 0.0 when omitted
[].e_g_factor body number No Generation factor; defaults to 0.0 when omitted

Example

curl -X PUT https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/meter_dynamic_parameters/7c9e6679-7425-40de-944b-e07fc1f90ae7 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '[
    {"id": "b1e2c3d4-0000-4000-8000-000000000001", "l_buy": 0.18, "l_sell": 0.05, "e_c": 0.678, "e_g_factor": 0}
  ]'

Response

{ "message": "Meter parameters updated successfully" }

Warning

Fields missing from an object are written as 0.0, so send all four values every time. Rows whose id does not exist for that meter and community are silently skipped (the call still succeeds). A missing id or an invalid UUID is intended to return 400, but the blanket error handler turns it into 500 with the original message in detail.

Run Sizing

Build Payload and Run Simulation

POST /core/api/communities/{community_id}/payload/build_and_simulate

Starts the sizing simulation in the background (Celery task simulation_background_task, queue default). The task builds the rec_sizing input from the community data, solves the MILP (CPLEX solver) and stores the results, replacing all previous sizing results of the community.

Auth / permissions: no authentication or permission dependency is declared in the router code.

Parameter In Type Required Description
community_id path UUID Yes Community ID
start_date body date (YYYY-MM-DD) Yes First day of the sizing period
end_date body date (YYYY-MM-DD) Yes Last day of the sizing period (inclusive)

Example

curl -X POST https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/payload/build_and_simulate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"start_date": "2024-05-01", "end_date": "2024-05-31"}'

Response (202 Accepted)

{
  "message": "Simulation started in background",
  "task_id": "6f5b1a52-5d1c-4c0e-9a0b-2e8a1f3d9c10"
}

Tip

What the task needs (any gap makes the task fail; the HTTP call has already returned 202, so check GET /core/api/communities/{community_id}/tasks/{task_id}?group_task=false):

  • the period must not cross a business-validity boundary (error Operation crosses a business-context boundary on YYYY-MM-DD);
  • general parameters for the community (No general static parameters found);
  • meters of type CPE that have at least one contract; other meter types are not simulated;
  • opportunity costs (l_buy, l_sell) for every such CPE across the period (No opportunity cost data for meter ...);
  • loads for the period (Loads API) for consumption e_c and, when present, generation.

How inputs are assembled

  • SCPU and STORAGE resources are linked to a CPE through their meter's cpe_id (resources on internal meters under the CPE). An SCPU's generation_capacity becomes the initial PV capacity (p_gn_init); a STORAGE's nominal capacity, min_SOC, max_SOC, efficiencies and deg_cost become the initial storage parameters (efficiencies default to 90% when missing).
  • Missing static parameters become 0.0.
  • Generation factors (e_g_factor) come from the loads' generation normalized by the initial PV capacity. If no meter has generation data, hourly/15-minute PVGIS factors are fetched using the geocoded community address (the community must have an address).
  • nr_days is computed from the request dates, not from the stored general parameters.

The task result is Simulation completed successfully. or Simulation failed: <reason>.

Sizing Results

Get Sizing Simulation Results

GET /core/api/communities/{community_id}/sizing_simulation/results

Returns the stored results of the last sizing run, one row per meter and time step, ordered by datetime_timestamp.

Auth / permissions: no authentication or permission dependency is declared in the router code.

Parameter In Type Required Description
community_id path UUID Yes Community ID
start_date query string (YYYY-MM-DD) No Keep rows from this day, interpreted as 00:00 UTC
end_date query string (YYYY-MM-DD) No Keep rows up to 23:59:59 of this day (UTC)
meter_id query UUID No Return only this meter's rows

Example

curl "https://<host>/core/api/communities/3fa85f64-5717-4562-b3fc-2c963f66afa6/sizing_simulation/results?start_date=2024-05-01&end_date=2024-05-02&meter_id=7c9e6679-7425-40de-944b-e07fc1f90ae7" \
  -H "Authorization: Bearer $TOKEN"

Response (abridged)

[
  {
    "datetime_timestamp": "2024-05-01T01:00:00+01:00",
    "meter_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "community_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "obj_value": 1234.56,
    "milp_status": "Optimal",
    "p_cont": 6.9,
    "p_gn_new": 12.0,
    "p_gn_total": 12.0,
    "e_bn_new": 10.0,
    "e_bn_total": 10.0,
    "e_cmet": 0.45,
    "e_g": 0.0,
    "e_sup": 0.45,
    "e_sur": 0.0,
    "e_bat": 5.0,
    "dual_prices": 0.07
  }
]

Fields per row (all numeric fields are nullable). Meter-level values (p_*, e_bn_*, c_ind2pool) repeat on every time step of that meter; obj_value, milp_status, delta_rec_balance and dual_prices are community-level values repeated on every row.

Group Fields Meaning
Identification datetime_timestamp, meter_id, community_id Time step start, CPE meter, community
Solution obj_value, milp_status Objective value and solver status
Sizing decisions p_cont, p_gn_new, p_gn_total, e_bn_new, e_bn_total Contracted power, new / total PV capacity (kW), new / total battery capacity (kWh)
Energy flows e_cmet, e_g, e_bc, e_bd, e_bat, e_sup, e_sur, e_consumed Meter consumption, PV generation, battery charge / discharge / stored energy, retailer supply, surplus, energy consumed
Local market e_pur_pool, e_sale_pool, e_slc_pool, e_alc, c_ind2pool Pool purchase / sale / selection, allocated energy, individual contribution to the pool
Deltas and prices delta_sup, delta_slc, delta_coeff, delta_rec_balance, delta_meter_balance, dual_prices Auxiliary solver variables and dual prices

Tip

Returns 404 (No simulation results found for the given criteria.) instead of an empty list when nothing matches, and 400 for a date not in YYYY-MM-DD format. Time steps start at start_date 00:00 UTC of the run and advance by 15 minutes (delta_t = 0.25) or 60 minutes (delta_t = 1); timestamps are returned converted to Europe/Lisbon. The optional EV and EWH series of the solver output are not stored or returned. Each new run deletes all earlier results of the community.

Simulator

The simulator endpoints belong to the Simulation operation mode (see the Overview): they build a community from a simulator export and run the operational tasks on it. The router requires is_allowed and get_current_user.

Create a Community from a Simulator Export

POST /core/api/simulator

Creates a DEMO community together with its members, meters, resources, ownerships, RESP, contracts, fixed bilateral prices and (optionally) ERSE, loads and DSO files, in one multipart request. The caller becomes the community admin.

Auth / permissions: platform admin (SUPER_USER) only. The path has no community, so the permission rules reject any other role's write request with 403 (Only super-users can perform this action).

Parameter In Type Required Description
basic_info form JSON string (object) Yes community_name, community_identifier, allocation, start_date (required); end_date; community_or_aggregator_type (default EGAC); market_rate (default VANILLA_IMR); market_divisor (0.5); market_compensation (0.5); market_small_increment (0.1); market_fixed_price (0.0805)
members form JSON string (array) Yes name, pre_id (UUID chosen by the client), is_host, is_promoter, start_date, end_date
meters form JSON string (array) Yes name (becomes the identifier), pre_id, type (CPE, INTERNAL, AGGREGATOR_METER), cpe (pre_id of the parent CPE for internal meters), installation_type (IC, IPR, IA, IAC), production_identifier, start_date, end_date
resources form JSON string (array) Yes name, pre_id, type, sumCertifiedPower, voltageLevel, type-specific camelCase fields (for example generationCapacity, nominalCapacity, maxPower, minSOC), ownerships (member pre_id, perc, dates), optional meter (pre_id), start_date, end_date
resp form JSON string (array) Yes provider_meter_id, receiver_meter_id (meter pre_ids), is_active, start_date, end_date
contracts form JSON string (array) Yes member (pre_id), optional meter (pre_id of a CPE/aggregator meter), buy_type, sell_type, voltage_level, tariff_cycle, with_holidays, contracted_power, start_date (alias validity), end_date, buy_payload, sell_payload
fixed_bilateral_prices form JSON string (array) No provider_user_id, receiver_user_id (member pre_ids), price, start_date, end_date
loads_files file (repeatable) CSV No Loads files, validated and imported synchronously
dso_file file DSO file No Validated and imported synchronously
erse_tariffs file (repeatable) file No Only the first file is used
erse_losses file (repeatable) file No Every file is imported

Enumerations are in Enums & Constants, community fields in Create a Community, and the equivalent single-call preload flow in Create a community in One Call.

Example

curl -X POST https://<host>/core/api/simulator \
  -H "Authorization: Bearer $TOKEN" \
  -F 'basic_info={"community_name":"Demo REC","community_identifier":"demo-rec","allocation":"PROPORTIONAL","start_date":"2024-01-01"}' \
  -F 'members=[{"name":"Alice","pre_id":"11111111-1111-4111-8111-111111111111","is_host":true,"start_date":"2024-01-01"}]' \
  -F 'meters=[{"name":"CPE-A","pre_id":"22222222-2222-4222-8222-222222222222","type":"CPE","cpe":"22222222-2222-4222-8222-222222222222","installation_type":"IAC","start_date":"2024-01-01"}]' \
  -F 'resources=[{"name":"PV-A","pre_id":"33333333-3333-4333-8333-333333333333","type":"SCPU","sumCertifiedPower":10,"voltageLevel":"BTN>","generationCapacity":10,"ownerships":[{"member":"11111111-1111-4111-8111-111111111111","perc":100,"start_date":"2024-01-01"}],"start_date":"2024-01-01"}]' \
  -F 'resp=[]' \
  -F 'contracts=[{"member":"11111111-1111-4111-8111-111111111111","meter":"22222222-2222-4222-8222-222222222222","buy_type":"FIXED","sell_type":"FIXED","voltage_level":"BTN>","tariff_cycle":"BI_DIARIO","with_holidays":false,"contracted_power":6.9,"start_date":"2024-01-01"}]' \
  -F "loads_files=@loads.csv;type=text/csv"

Response (201 Created)

{ "message": "Simulation started" }

Tip

The response does not contain the new community ID; look it up afterwards by its identifier (for example with GET /core/api/communities). The pre_id values are client-side IDs used only to cross-reference the arrays in the same request; the real IDs are generated by the platform. Members get a generated email (email.<name>@cer.com) and address.

Validation raised by the route: 409 for duplicate resource names (case-insensitive, trimmed) and for two resources on the same CPE or internal meter in overlapping periods (add internal meters instead); 422 for a resource linked to an unknown or invalid meter; 400 for a contract that references an unknown CPE meter. Malformed JSON or schema violations in the form fields are parsed manually and are not converted to 422. The route has no surrounding rollback, so a failure halfway can leave a partially created community.

When contracts[].meter is omitted (legacy simulator files), contracts are matched by position to the CPE and aggregator meters, in order. Loads files must be text/csv (see Loads API). The community is created with the periods from start_date / end_date; see Business Validity.

Run a Simulation Task

POST /core/api/simulator/{community_id}/simulationtask/{task_name}

Triggers one of a fixed set of asynchronous operations on a community, mainly to re-run history in simulation mode. Each branch queues a Celery task and returns its ID.

Auth / permissions: is_allowed on the community: platform admin or community admin (a plain member gets 403 because this is a POST). The community must exist (404 otherwise).

Parameter In Type Required Description
community_id path UUID Yes Community ID
task_name path string Yes One of calculate_opportunity_costs, open_sessions, clear_market, run_settlement, run_pre_delivery_energy_management
start_date body date Depends Required by calculate_opportunity_costs; optional for open_sessions
end_date body date Depends Required by calculate_opportunity_costs; optional for open_sessions
use_dso_measurements body boolean No Default false. Used by clear_market and run_settlement
task_name Effect Body fields used
calculate_opportunity_costs Computes opportunity costs between the dates (feeds sizing; see Run Sizing) start_date, end_date
open_sessions Opens all sessions of the community, optionally limited to the dates start_date, end_date
clear_market Clears the local market (Market) use_dso_measurements
run_settlement Runs settlement use_dso_measurements
run_pre_delivery_energy_management Calculates EMS setpoints for the community (Energy Management) none

Example

curl -X POST https://<host>/core/api/simulator/3fa85f64-5717-4562-b3fc-2c963f66afa6/simulationtask/clear_market \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"use_dso_measurements": false}'

Response (abridged)

{
  "message": "Processing started",
  "task_id": "6f5b1a52-5d1c-4c0e-9a0b-2e8a1f3d9c10"
}

Tip

An unknown task_name is not rejected: the endpoint returns 200 with a null body. For calculate_opportunity_costs the body is mandatory; omitting it fails with 500. Poll GET /core/api/communities/{community_id}/tasks/{task_id}?group_task=false for task status.

Warning

The function signature exposes a db_url parameter with a default taken from the server settings, which FastAPI publishes as an optional query parameter. It is meant for internal use; do not set it from clients.