Initial Cariflex project

- 40 FlexMeasures assets (10 PV, 10 Bat, 10 Chg, 10 EV)
- Geolocated on Martinique
- Documentation: architecture, deployment, concepts
- Standards: Flex Ready, S2, OpenADR, EPEX SPOT
- R&D tools: HAMLET, OPLEM, lemlab
- Map patch: Mapbox -> OpenStreetMap
This commit is contained in:
Eric F
2026-06-07 22:19:29 -04:00
commit ffc08d0629
18 changed files with 1229 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env python3
"""Re-localise les assets Cariflex sur la Martinique."""
import subprocess, random
def run_sql(query):
subprocess.run([
"docker", "exec", "flexmeasures-db", "psql", "-U", "flexmeasures", "-d", "flexmeasures",
"-t", "-c", query
], capture_output=True, text=True)
# Martinique bounding box (approximate)
# Lat: 14.38 to 14.87, Lon: -61.25 to -60.82
# But we need to avoid the sea - use known land areas
# Realistic zones on Martinique (lat, lon) - major towns and industrial zones
ZONES = [
# Fort-de-France area (capital, dense urban)
(14.6091, -61.2155), # Fort-de-France center
(14.6150, -61.2080), # Fort-de-France north
(14.6050, -61.2200), # Fort-de-France south
(14.6200, -61.2000), # Fort-de-France east
(14.5950, -61.2100), # Fort-de-France west
# Le Lamentin (airport, industrial zone)
(14.6100, -61.0100), # Le Lamentin center
(14.6150, -61.0050), # Airport area
(14.6050, -61.0200), # Industrial zone
# Sainte-Marie (north-east)
(14.7800, -60.9800), # Sainte-Marie town
(14.7900, -60.9700), # North coast
# Le Robert (north-east coast)
(14.6800, -60.9400), # Le Robert town
# Le François (south-east coast)
(14.6600, -60.9000), # Le François town
# Le Vauclin (south-east tip)
(14.5500, -60.8400), # Le Vauclin
# Le Marin (south)
(14.4700, -60.8700), # Le Marin town
# Sainte-Anne (south coast)
(14.4400, -60.8500), # Sainte-Anne
# Le Diamant (south-west)
(14.4800, -61.0200), # Le Diamant
# Les Anses-d'Arlet (south-west coast)
(14.5000, -61.0800), # Les Anses-d'Arlet
# Sainte-Luce (south-east)
(14.4600, -60.9300), # Sainte-Luce
# Le Lorrain (north)
(14.7200, -60.9300), # Le Lorrain
]
random.seed(42) # Reproducible
# Shuffle zones and pick 10 for each asset type (with some overlap for co-location)
random.shuffle(ZONES)
# Get all assets ordered by type and name
result = subprocess.run([
"docker", "exec", "flexmeasures-db", "psql", "-U", "flexmeasures", "-d", "flexmeasures",
"-t", "-c", """
SELECT g.id, g.name, gt.name as type_name
FROM generic_asset g
JOIN generic_asset_type gt ON g.generic_asset_type_id = gt.id
ORDER BY gt.id, g.name;
"""
], capture_output=True, text=True)
assets = []
for line in result.stdout.strip().split('\n'):
parts = [p.strip() for p in line.split('|')]
if len(parts) == 3:
assets.append((int(parts[0]), parts[1], parts[2]))
# Assign random locations per type (4 types, 10 assets each)
type_groups = {}
for aid, name, atype in assets:
if atype not in type_groups:
type_groups[atype] = []
type_groups[atype].append((aid, name))
zone_idx = 0
for atype, group in type_groups.items():
# Pick 10 random zones for this type (zones can repeat slightly for density)
type_zones = [ZONES[i % len(ZONES)] for i in range(zone_idx, zone_idx + 10)]
random.shuffle(type_zones)
zone_idx += 10
for i, (aid, name) in enumerate(group):
lat, lon = type_zones[i]
# Add small random jitter (±0.005 degrees ≈ 500m)
lat += random.uniform(-0.005, 0.005)
lon += random.uniform(-0.005, 0.005)
run_sql("UPDATE generic_asset SET latitude = {}, longitude = {} WHERE id = {};".format(
round(lat, 6), round(lon, 6), aid))
print(" {} ({}) -> {:.4f}, {:.4f}".format(name, atype[:3], lat, lon))
print("\nDone!")