diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml
index c05343d70..7a9fb3e66 100644
--- a/.github/workflows/docs.yaml
+++ b/.github/workflows/docs.yaml
@@ -57,7 +57,31 @@ jobs:
- name: Install dependencies
run: uv pip install --system ".[docs,full]"
+ - name: Get notebook cache key
+ id: notebook-cache-key
+ run: |
+ # Hash notebooks + flixopt source code (sorted for stable cache keys)
+ HASH=$(find docs/notebooks -name '*.ipynb' | sort | xargs cat | cat - <(find flixopt -name '*.py' | sort | xargs cat) | sha256sum | cut -d' ' -f1)
+ echo "hash=$HASH" >> $GITHUB_OUTPUT
+
+ - name: Cache executed notebooks
+ uses: actions/cache@v4
+ id: notebook-cache
+ with:
+ path: docs/notebooks/*.ipynb
+ key: notebooks-${{ steps.notebook-cache-key.outputs.hash }}
+
+ - name: Execute notebooks in parallel
+ if: steps.notebook-cache.outputs.cache-hit != 'true'
+ run: |
+ # Execute all notebooks in parallel (4 at a time)
+ # Run from notebooks directory so relative imports work
+ cd docs/notebooks && find . -name '*.ipynb' -print0 | \
+ xargs -0 -P 4 -I {} jupyter execute --inplace {}
+
- name: Build docs
+ env:
+ MKDOCS_JUPYTER_EXECUTE: "false"
run: mkdocs build --strict
- uses: actions/upload-artifact@v4
@@ -95,12 +119,34 @@ jobs:
- name: Install dependencies
run: uv pip install --system ".[docs,full]"
+ - name: Get notebook cache key
+ id: notebook-cache-key
+ run: |
+ # Hash notebooks + flixopt source code (sorted for stable cache keys)
+ HASH=$(find docs/notebooks -name '*.ipynb' | sort | xargs cat | cat - <(find flixopt -name '*.py' | sort | xargs cat) | sha256sum | cut -d' ' -f1)
+ echo "hash=$HASH" >> $GITHUB_OUTPUT
+
+ - name: Cache executed notebooks
+ uses: actions/cache@v4
+ id: notebook-cache
+ with:
+ path: docs/notebooks/*.ipynb
+ key: notebooks-${{ steps.notebook-cache-key.outputs.hash }}
+
+ - name: Execute notebooks in parallel
+ if: steps.notebook-cache.outputs.cache-hit != 'true'
+ run: |
+ cd docs/notebooks && find . -name '*.ipynb' -print0 | \
+ xargs -0 -P 4 -I {} jupyter execute --inplace {}
+
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Deploy docs
+ env:
+ MKDOCS_JUPYTER_EXECUTE: "false"
run: |
VERSION=${{ inputs.version }}
VERSION=${VERSION#v}
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index f30c2b5cb..18b1eb4be 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -7,7 +7,7 @@ repos:
- id: check-yaml
exclude: ^mkdocs\.yml$ # Skip mkdocs.yml
- id: check-added-large-files
- exclude: .*Zeitreihen2020\.csv$
+ exclude: (.*Zeitreihen2020\.csv$|docs/notebooks/data/raw/.*)
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.4
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b9a30f3a8..bad4e4d52 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -51,6 +51,259 @@ If upgrading from v2.x, see the [v3.0.0 release notes](https://github.com/flixOp
Until here -->
+## [6.0.0] - Upcoming
+
+**Summary**: Major release introducing time-series clustering with storage inter-cluster linking, the new `fxplot` accessor for universal xarray plotting, and removal of deprecated v5.0 classes. Includes configurable storage behavior across typical periods and improved weights API.
+
+!!! warning "Breaking Changes"
+ This release removes `ClusteredOptimization` and `ClusteringParameters` which were deprecated in v5.0.0. Use `flow_system.transform.cluster()` instead. See [Migration](#migration-from-clusteredoptimization) below.
+
+### β¨ Added
+
+**FlowSystem Comparison**: New `Comparison` class for comparing multiple FlowSystems side-by-side:
+
+```python
+# Compare systems (uses FlowSystem.name by default)
+comp = fx.Comparison([fs_base, fs_modified])
+
+# Or with custom names
+comp = fx.Comparison([fs1, fs2, fs3], names=['baseline', 'low_cost', 'high_eff'])
+
+# Side-by-side plots (auto-facets by 'case' dimension)
+comp.statistics.plot.balance('Heat')
+comp.statistics.flow_rates.fxplot.line()
+
+# Access combined data with 'case' dimension
+comp.solution # xr.Dataset
+comp.statistics.flow_rates # xr.Dataset
+
+# Compute differences relative to a reference case
+comp.diff() # vs first case
+comp.diff('baseline') # vs named case
+```
+
+- Concatenates solutions and statistics from multiple FlowSystems with a `'case'` dimension
+- Mirrors all `StatisticsAccessor` properties (`flow_rates`, `flow_hours`, `sizes`, `charge_states`, `temporal_effects`, `periodic_effects`, `total_effects`)
+- Mirrors all `StatisticsPlotAccessor` methods (`balance`, `carrier_balance`, `flows`, `sizes`, `duration_curve`, `effects`, `charge_states`, `heatmap`, `storage`)
+- Existing plotting infrastructure automatically handles faceting by `'case'`
+
+**Time-Series Clustering**: Reduce large time series to representative typical periods for faster investment optimization, then expand results back to full resolution.
+
+```python
+# Stage 1: Cluster and optimize (fast sizing)
+fs_clustered = flow_system.transform.cluster(
+ n_clusters=12, # 12 typical days from a year
+ cluster_duration='1D', # Each cluster represents one day
+ time_series_for_high_peaks=['HeatDemand(Q)|fixed_relative_profile'],
+)
+fs_clustered.optimize(solver)
+
+# Stage 2: Expand back to full resolution
+fs_expanded = fs_clustered.transform.expand_solution()
+```
+
+**Storage Modes for Clustering**: Control how storage behaves across clustered periods via `Storage(cluster_mode=...)`:
+
+| Mode | Description | Use Case |
+|------|-------------|----------|
+| `'intercluster_cyclic'` | Links storage across clusters + yearly cyclic (default) | Seasonal storage with yearly optimization |
+| `'intercluster'` | Links storage across clusters, free start/end | Multi-year optimization without cyclic constraint |
+| `'cyclic'` | Each cluster independent, but cyclic (start = end) | Daily storage only, ignores seasonal patterns |
+| `'independent'` | Each cluster fully independent, free start/end | Fastest solve, no long-term storage value |
+
+**Clustering Parameters**:
+
+- `n_clusters` (int): Number of representative periods to create
+- `cluster_duration` (str): Duration of each cluster period (e.g., `'1D'`, `'24h'`, or integer hours)
+- `time_series_for_high_peaks` (list[str]): Ensure clusters containing peak values are captured
+- `time_series_for_low_peaks` (list[str]): Ensure clusters containing minimum values are captured
+
+**Key Features**:
+
+- **Inter-cluster storage linking**: For `'intercluster'` and `'intercluster_cyclic'` modes, a `SOC_boundary` variable tracks absolute state-of-charge at period boundaries, enabling accurate seasonal storage modeling
+- **Self-discharge decay**: Storage losses are correctly applied during solution expansion using the formula: `actual_SOC(t) = SOC_boundary Γ (1 - loss)^t + ΞE(t)`
+- **Multi-dimensional support**: Works with periods, scenarios, and clusters dimensions simultaneously
+- **Solution expansion**: `transform.expand_solution()` maps clustered results back to original timesteps with proper storage state reconstruction
+
+**Example: Seasonal Storage with Clustering**:
+
+```python
+# Configure storage for seasonal behavior
+storage = fx.Storage(
+ 'SeasonalPit',
+ capacity_in_flow_hours=5000,
+ cluster_mode='intercluster_cyclic', # Enable seasonal storage in clustering
+ relative_loss_per_hour=0.0001, # Small self-discharge
+ ...
+)
+
+# Cluster, optimize, and expand
+fs_clustered = flow_system.transform.cluster(n_clusters=12, cluster_duration='1D')
+fs_clustered.optimize(solver)
+fs_expanded = fs_clustered.transform.expand_solution()
+
+# Full-resolution charge state now available
+charge_state = fs_expanded.solution['SeasonalPit|charge_state']
+```
+
+!!! tip "Choosing the Right Storage Mode"
+ Use `'intercluster_cyclic'` (default) for seasonal storage like pit storage or underground thermal storage.
+ Use `'cyclic'` for short-term storage like batteries or hot water tanks where only daily patterns matter.
+ Use `'independent'` for quick estimates when storage behavior isn't critical.
+
+**FXPlot Accessor**: New global xarray accessors for universal plotting with automatic faceting and smart dimension handling. Works on any xarray Dataset, not just flixopt results.
+
+```python
+import flixopt as fx # Registers accessors automatically
+
+# Plot any xarray Dataset with automatic faceting
+dataset.fxplot.bar(x='component')
+dataset.fxplot.area(x='time')
+dataset.fxplot.heatmap(x='time', y='component')
+dataset.fxplot.line(x='time', facet_col='scenario')
+
+# DataArray support
+data_array.fxplot.line()
+
+# Statistics transformations
+dataset.fxstats.to_duration_curve()
+```
+
+**Available Plot Methods**:
+
+| Method | Description |
+|--------|-------------|
+| `.fxplot.bar()` | Grouped bar charts |
+| `.fxplot.stacked_bar()` | Stacked bar charts |
+| `.fxplot.line()` | Line charts with faceting |
+| `.fxplot.area()` | Stacked area charts |
+| `.fxplot.heatmap()` | Heatmap visualizations |
+| `.fxplot.scatter()` | Scatter plots |
+| `.fxplot.pie()` | Pie charts with faceting |
+| `.fxstats.to_duration_curve()` | Transform to duration curve format |
+
+**Key Features**:
+
+- **Auto-faceting**: Automatically assigns extra dimensions (period, scenario, cluster) to `facet_col`, `facet_row`, or `animation_frame`
+- **Smart x-axis**: Intelligently selects x dimension based on priority (time > duration > period > scenario)
+- **Universal**: Works on any xarray Dataset/DataArray, not limited to flixopt
+- **Configurable**: Customize via `CONFIG.Plotting` (colorscales, facet columns, line shapes)
+
+### π₯ Breaking Changes
+
+- `FlowSystem.scenario_weights` are now always normalized to sum to 1 when set (including after `.sel()` subsetting)
+
+### β»οΈ Changed
+
+- `FlowSystem.weights` returns `dict[str, xr.DataArray]` (unit weights instead of `1.0` float fallback)
+- `FlowSystemDimensions` type now includes `'cluster'`
+
+### ποΈ Deprecated
+
+The following items are deprecated and will be removed in **v7.0.0**:
+
+**Classes** (use FlowSystem methods instead):
+
+- `Optimization` class β Use `flow_system.optimize(solver)`
+- `SegmentedOptimization` class β Use `flow_system.optimize.rolling_horizon()`
+- `Results` class β Use `flow_system.solution` and `flow_system.statistics`
+- `SegmentedResults` class β Use segment FlowSystems directly
+
+**FlowSystem methods** (use `transform` or `topology` accessor instead):
+
+- `flow_system.sel()` β Use `flow_system.transform.sel()`
+- `flow_system.isel()` β Use `flow_system.transform.isel()`
+- `flow_system.resample()` β Use `flow_system.transform.resample()`
+- `flow_system.plot_network()` β Use `flow_system.topology.plot()`
+- `flow_system.start_network_app()` β Use `flow_system.topology.start_app()`
+- `flow_system.stop_network_app()` β Use `flow_system.topology.stop_app()`
+- `flow_system.network_infos()` β Use `flow_system.topology.infos()`
+
+**Parameters:**
+
+- `normalize_weights` parameter in `create_model()`, `build_model()`, `optimize()`
+
+**Topology method name simplifications** (old names still work with deprecation warnings, removal in v7.0.0):
+
+| Old (v5.x) | New (v6.0.0) |
+|------------|--------------|
+| `topology.plot_network()` | `topology.plot()` |
+| `topology.start_network_app()` | `topology.start_app()` |
+| `topology.stop_network_app()` | `topology.stop_app()` |
+| `topology.network_infos()` | `topology.infos()` |
+
+Note: `topology.plot()` now renders a Sankey diagram. The old PyVis visualization is available via `topology.plot_legacy()`.
+
+### π₯ Removed
+
+**Clustering classes removed** (deprecated in v5.0.0):
+
+- `ClusteredOptimization` class - Use `flow_system.transform.cluster()` then `optimize()`
+- `ClusteringParameters` class - Parameters are now passed directly to `transform.cluster()`
+- `flixopt/clustering.py` module - Restructured to `flixopt/clustering/` package with new classes
+
+#### Migration from ClusteredOptimization
+
+=== "v5.x (Old - No longer works)"
+ ```python
+ from flixopt import ClusteredOptimization, ClusteringParameters
+
+ params = ClusteringParameters(hours_per_period=24, nr_of_periods=8)
+ calc = ClusteredOptimization('model', flow_system, params)
+ calc.do_modeling_and_solve(solver)
+ results = calc.results
+ ```
+
+=== "v6.0.0 (New)"
+ ```python
+ # Cluster using transform accessor
+ fs_clustered = flow_system.transform.cluster(
+ n_clusters=8, # was: nr_of_periods
+ cluster_duration='1D', # was: hours_per_period=24
+ )
+ fs_clustered.optimize(solver)
+
+ # Results on the clustered FlowSystem
+ costs = fs_clustered.solution['costs'].item()
+
+ # Expand back to full resolution if needed
+ fs_expanded = fs_clustered.transform.expand_solution()
+ ```
+
+### π Fixed
+
+- `temporal_weight` and `sum_temporal()` now use consistent implementation
+
+### π Docs
+
+**New Documentation Pages:**
+
+- [Time-Series Clustering Guide](https://flixopt.github.io/flixopt/latest/user-guide/optimization/clustering/) - Comprehensive guide to clustering workflows
+
+**New Jupyter Notebooks:**
+
+- **08c-clustering.ipynb** - Introduction to time-series clustering
+- **08c2-clustering-storage-modes.ipynb** - Comparison of all 4 storage cluster modes
+- **08d-clustering-multiperiod.ipynb** - Clustering with periods and scenarios
+- **08e-clustering-internals.ipynb** - Understanding clustering internals
+- **fxplot_accessor_demo.ipynb** - Demo of the new fxplot accessor
+
+### π· Development
+
+**New Test Suites for Clustering**:
+
+- `TestStorageClusterModes`: Tests for all 4 storage `cluster_mode` options
+- `TestInterclusterStorageLinking`: Tests for `SOC_boundary` variable and expansion logic
+- `TestMultiPeriodClustering`: Tests for clustering with periods and scenarios dimensions
+- `TestPeakSelection`: Tests for `time_series_for_high_peaks` and `time_series_for_low_peaks` parameters
+
+**New Test Suites for Other Features**:
+
+- `test_clustering_io.py` - Tests for clustering serialization roundtrip
+- `test_sel_isel_single_selection.py` - Tests for transform selection methods
+
+---
+
## [5.0.4] - 2026-01-05
**Summary**: Dependency updates.
diff --git a/docs/design/cluster_architecture.md b/docs/design/cluster_architecture.md
new file mode 100644
index 000000000..e90aeccff
--- /dev/null
+++ b/docs/design/cluster_architecture.md
@@ -0,0 +1,773 @@
+# Design Document: Cluster Architecture for flixopt
+
+## Executive Summary
+
+This document defines the architecture for cluster representation in flixopt using **true `(cluster, time)` dimensions**.
+
+### Key Decision: True Dimensions (Option B)
+
+**Chosen Approach:**
+```python
+# Clustered data structure:
+data.dims = ('cluster', 'time', 'period', 'scenario')
+data.shape = (9, 24, ...) # 9 clusters Γ 24 timesteps each
+```
+
+**Why True Dimensions?**
+1. **Temporal constraints just work** - `x[:, 1:] - x[:, :-1]` naturally stays within clusters
+2. **No boundary masking** - StorageModel, StatusModel constraints are clean and vectorized
+3. **Plotting trivial** - existing `facet_col='cluster'` works automatically
+
+### Document Scope
+
+1. Current architecture analysis (Part 1)
+2. Architectural options and recommendation (Part 2)
+3. Impact on Features - StatusModel, StorageModel, etc. (Part 3)
+4. Plotting improvements (Part 4)
+5. Future considerations (Part 5)
+6. Implementation roadmap (Part 6)
+
+---
+
+## Part 1: Current Architecture Analysis
+
+### 1.1 Time Dimension Structure
+
+**Current Implementation:**
+```
+time: (n_clusters Γ timesteps_per_cluster,) # Flat, e.g., (864,) for 9 clusters Γ 96 timesteps
+```
+
+**Key Properties:**
+- `cluster_weight`: Shape `(time,)` with repeated values per cluster
+- `timestep_duration`: Shape `(time,)` or scalar
+- `aggregation_weight = timestep_duration Γ cluster_weight`
+
+**Cluster Tracking:**
+- `cluster_start_positions`: Array of indices where each cluster begins
+- `ClusterStructure`: Stores cluster_order, occurrences, n_clusters, timesteps_per_cluster
+
+### 1.2 Features Affected by Time Structure
+
+| Feature | Time Usage | Clustering Impact |
+|---------|-----------|-------------------|
+| **StatusModel** | `aggregation_weight` for active hours, `timestep_duration` for effects | Must sum correctly across clusters |
+| **InvestmentModel** | Periodic (no time dim) | Unaffected by time structure |
+| **PiecewiseModel** | Per-timestep lambda variables | Must preserve cluster structure |
+| **ShareAllocationModel** | Uses `cluster_weight` explicitly | Directly depends on weight structure |
+| **StorageModel** | Charge balance across time | Needs cluster boundary handling |
+| **InterclusterStorageModel** | SOC_boundary linking | Uses cluster indices extensively |
+
+### 1.3 Current Plotting Structure
+
+**StatisticsPlotAccessor Methods:**
+- `balance()`: Node flow visualization
+- `storage()`: Dual-axis charge/discharge + SOC
+- `heatmap()`: 2D time reshaping (days Γ hours)
+- `duration_curve()`: Sorted load profiles
+- `effects()`: Cost/emission breakdown
+
+**Clustering in Plots:**
+- `ClusterStructure.plot()`: Shows cluster assignments
+- Cluster weight applied when aggregating (`cluster_weight.sum('time')`)
+- No visual separation between clusters in time series plots
+
+---
+
+## Part 2: Architectural Options
+
+### 2.1 Option A: Enhanced Flat with Indexers
+
+Keep flat `time` dimension, add xarray indexer properties.
+
+**Pros:** Supports variable-length clusters
+**Cons:** Every temporal constraint needs explicit boundary masking
+
+**NOT RECOMMENDED** - see Option B.
+
+### 2.2 Option B: True (cluster, time) Dimensions (RECOMMENDED)
+
+Reshape time to 2D when clustering is active:
+
+```python
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# DIMENSION STRUCTURE
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+
+# Non-clustered:
+data.dims = ('time', 'period', 'scenario')
+data.shape = (8760, ...) # Full year hourly
+
+# Clustered:
+data.dims = ('cluster', 'time', 'period', 'scenario')
+data.shape = (9, 24, ...) # 9 clusters Γ 24 timesteps each
+
+# Varying segment durations supported:
+timestep_duration.dims = ('cluster', 'time')
+timestep_duration.shape = (9, 24) # Different durations per segment per cluster
+```
+
+**Key Benefits - Temporal Constraints Just Work!**
+
+```python
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# STORAGE: Charge balance naturally within clusters
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# charge_state shape: (cluster, time+1, period, scenario) - extra timestep for boundaries
+charge_state = ... # (9, 25, ...)
+
+# Balance constraint - NO MASKING NEEDED!
+lhs = charge_state[:, 1:] - charge_state[:, :-1] * (1 - loss) - charge + discharge
+# Shape: (cluster, time, period, scenario) = (9, 24, ...)
+
+# Delta per cluster (for inter-cluster linking):
+delta_soc = charge_state[:, -1] - charge_state[:, 0] # Shape: (cluster, ...)
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# STATUS: Uptime/downtime constraints stay within clusters
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+status = ... # (cluster, time, ...)
+
+# State transitions - naturally per cluster!
+activate = status[:, 1:] - status[:, :-1] # No boundary issues!
+
+# min_uptime constraint - works correctly, can't span clusters
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# INTER-CLUSTER OPERATIONS
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# Select first/last timestep of each cluster:
+at_start = data.isel(time=0) # Shape: (cluster, period, scenario)
+at_end = data.isel(time=-1) # Shape: (cluster, period, scenario)
+
+# Compute per-cluster statistics:
+mean_per_cluster = data.mean(dim='time')
+max_per_cluster = data.max(dim='time')
+```
+
+**Varying Segment Durations (Future Segmentation):**
+
+```python
+# Same NUMBER of segments per cluster, different DURATIONS:
+timestep_duration = xr.DataArray(
+ [
+ [2, 2, 1, 1, 2, 4], # Cluster 0: segments sum to 12h
+ [1, 3, 2, 2, 2, 2], # Cluster 1: segments sum to 12h
+ ...
+ ],
+ dims=['cluster', 'time'],
+ coords={'cluster': range(9), 'time': range(6)}
+)
+
+# aggregation_weight still works:
+aggregation_weight = timestep_duration * cluster_weight # (cluster, time) * (cluster,)
+```
+
+**Pros:**
+- Temporal constraints naturally stay within clusters - NO MASKING!
+- StatusModel uptime/downtime just works
+- Storage balance is clean
+- Much less code, fewer bugs
+- Supports varying segment durations (same count, different lengths)
+
+**Cons:**
+- More upfront refactoring
+- All code paths need to handle `(cluster, time)` vs `(time,)` based on `is_clustered`
+
+### 2.3 Recommendation: Option B (True Dimensions)
+
+Given:
+- Uniform timestep COUNT per cluster (tsam default)
+- Variable segment DURATIONS supported via `timestep_duration[cluster, time]`
+- Much cleaner constraint handling
+
+**Option B is the recommended choice.**
+
+---
+
+## Part 3: Impact on Features
+
+### 3.1 StatusModel Impact - SOLVED BY TRUE DIMENSIONS
+
+**With `(cluster, time)` dimensions, temporal constraints naturally stay within clusters!**
+
+```python
+status.dims = ('cluster', 'time', 'period', 'scenario')
+status.shape = (9, 24, ...)
+
+# State transitions - per cluster, no boundary issues!
+activate = status[:, 1:] - status[:, :-1]
+
+# min_uptime constraint operates within each cluster's time dimension
+# Cannot accidentally span cluster boundaries
+```
+
+**What works automatically:**
+- β
`min_uptime`, `min_downtime` - constraints stay within clusters
+- β
`initial_status` - applies to each cluster's first timestep
+- β
State transitions - naturally per cluster
+- β
`active_hours` - uses `aggregation_weight` correctly
+- β
`effects_per_startup` - counted per cluster, weighted by `cluster_weight`
+
+**Optional Enhancement - cluster_mode for special cases:**
+```python
+class StatusParameters:
+ # NEW: How to handle cluster boundaries (default: independent)
+ cluster_mode: Literal['independent', 'cyclic'] = 'independent'
+```
+
+| Mode | Behavior |
+|------|----------|
+| `independent` | Each cluster starts fresh (default, most common) |
+| `cyclic` | `status[:, 0] == status[:, -1]` - status returns to start |
+
+### 3.2 StorageModel Impact - SIMPLIFIED
+
+**With `(cluster, time)` dimensions, storage constraints become trivial:**
+
+```python
+charge_state.dims = ('cluster', 'time_extra', 'period', 'scenario')
+charge_state.shape = (9, 25, ...) # 24 timesteps + 1 boundary per cluster
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# Charge balance - NO MASKING!
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+lhs = (
+ charge_state[:, 1:] -
+ charge_state[:, :-1] * (1 - loss_rate) -
+ charge * eta_charge +
+ discharge / eta_discharge
+)
+self.add_constraints(lhs == 0, name='charge_balance') # Clean!
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# Delta SOC per cluster (for inter-cluster linking)
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+delta_soc = charge_state[:, -1] - charge_state[:, 0] # Shape: (cluster, ...)
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# Cluster start constraint (relative SOC starts at 0)
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+self.add_constraints(charge_state[:, 0] == 0, name='cluster_start')
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# Cyclic constraint (optional)
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+self.add_constraints(charge_state[:, 0] == charge_state[:, -1], name='cyclic')
+```
+
+**InterclusterStorageModel also simplified** - SOC_boundary linking uses clean slicing.
+
+### 3.3 ShareAllocationModel Impact
+
+**Current Code (features.py:624):**
+```python
+self._eq_total.lhs -= (self.total_per_timestep * self._model.cluster_weight).sum(dim='time')
+```
+
+**With Enhanced Helpers:**
+No changes needed - `cluster_weight` structure preserved.
+
+### 3.4 PiecewiseModel Impact
+
+**Current Code:** Creates lambda variables per timestep.
+
+**With Enhanced Helpers:**
+No changes needed - operates on flat time dimension.
+
+### 3.5 Summary: Models with True (cluster, time) Dimensions
+
+| Model | Cross-Timestep Constraints | With True Dims | Action Needed |
+|-------|---------------------------|----------------|---------------|
+| **StorageModel** | `cs[t] - cs[t-1]` | β
Just works | Simplify code |
+| **StatusModel** | min_uptime, min_downtime | β
Just works | Optional cluster_mode |
+| **consecutive_duration_tracking** | State machine | β
Just works | No changes |
+| **state_transition_bounds** | `activate[t] - status[t-1]` | β
Just works | No changes |
+| **PiecewiseModel** | Per-timestep only | β
Just works | No changes |
+| **ShareAllocationModel** | Sum with cluster_weight | β
Just works | No changes |
+| **InvestmentModel** | No time dimension | β
Just works | No changes |
+
+**Key Insight:** With true `(cluster, time)` dimensions, `x[:, 1:] - x[:, :-1]` naturally stays within clusters!
+
+---
+
+## Part 4: Plotting Improvements
+
+### 4.1 Key Benefit of True Dimensions: Minimal Plotting Changes
+
+With true `(cluster, time)` dimensions, plotting becomes trivial because:
+1. Data already has the right shape - no reshaping needed
+2. Existing `facet_col='cluster'` parameter just works
+3. Only minimal changes needed: auto-add cluster separators in combined views
+
+### 4.2 Proposed Approach: Leverage Existing Infrastructure
+
+#### 4.2.1 Use Existing facet_col Parameter
+
+**No new plot methods needed!** The existing infrastructure handles `cluster` dimension:
+
+```python
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# EXISTING API - works automatically with (cluster, time) dims!
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+fs.statistics.plot.storage('Battery', facet_col='cluster') # One subplot per cluster
+fs.statistics.plot.balance('Heat', facet_col='cluster') # One subplot per cluster
+fs.statistics.plot.flows(..., facet_col='cluster') # Same pattern
+
+# Combine with other dimensions
+fs.statistics.plot.balance('Heat', facet_col='cluster', facet_row='scenario')
+```
+
+#### 4.2.2 Auto-Add Cluster Separators (Small Change)
+
+For combined views (no faceting), add visual separators:
+
+```python
+def _create_base_plot(self, data, **kwargs):
+ """Base plot creation - add cluster separators if combined view."""
+ fig = ... # existing logic
+
+ # Auto-add cluster separators if clustered and showing combined time
+ if self._fs.is_clustered and 'cluster' not in kwargs.get('facet_col', ''):
+ # Add subtle vertical lines between clusters
+ for cluster_idx in range(1, self._fs.clustering.n_clusters):
+ x_pos = cluster_idx * self._fs.clustering.timesteps_per_cluster
+ fig.add_vline(x=x_pos, line_dash='dot', opacity=0.3, line_color='gray')
+
+ return fig
+```
+
+#### 4.2.3 Per-Cluster Statistics (Natural with True Dims)
+
+With `(cluster, time)` dimensions, aggregation is trivial:
+
+```python
+# Mean per cluster - just use xarray
+mean_per_cluster = data.mean(dim='time') # Shape: (cluster, ...)
+max_per_cluster = data.max(dim='time')
+
+# Can plot directly
+fs.statistics.plot.bar(data.mean('time'), x='cluster', title='Mean by Cluster')
+```
+
+#### 4.2.4 Heatmap (Already Correct Shape)
+
+With true dimensions, heatmaps work directly:
+
+```python
+# Data already has (cluster, time) shape - heatmap just works!
+def cluster_heatmap(self, variable):
+ data = self._get_variable(variable)
+
+ # With (cluster, time) dims, no reshaping needed!
+ return self._plot_heatmap(
+ data, # Already (cluster, time, ...)
+ x='time',
+ y='cluster',
+ colorbar_title=variable
+ )
+```
+
+### 4.3 Summary: Plotting Changes Required
+
+| Change | Scope | Complexity |
+|--------|-------|------------|
+| Auto cluster separators in base plot | ~10 lines in `_create_base_plot` | Low |
+| Ensure facet_col='cluster' works | Should work already | None |
+| Heatmap with cluster dim | Works automatically | None |
+| No new plot methods needed | - | - |
+
+---
+
+## Part 5: Future Considerations
+
+### 5.1 Variable Segment Durations (Out of Scope)
+
+tsam supports intra-period segmentation with variable segment durations. This could be supported in the future via:
+- Integer-based `time` index (0, 1, 2, ...) instead of timestamps
+- `timestep_duration[cluster, time]` array for variable durations per segment
+
+**Not implemented in initial version** - the architecture supports it, but it's not a priority.
+
+---
+
+## Part 6: Implementation Roadmap
+
+### Phase 1: Core Dimension Refactoring (PRIORITY)
+
+**Goal:** Introduce true `(cluster, time)` dimensions throughout the codebase.
+
+**Tasks:**
+1. Update `FlowSystem` to support `(cluster, time)` dimension structure when clustered
+2. Add `is_clustered` property to `FlowSystem`
+3. Update `Clustering` class with:
+ - `n_clusters: int` property
+ - `timesteps_per_cluster: int` property
+ - Coordinate accessors for cluster dimension
+4. Update `cluster_weight` to have shape `(cluster,)` instead of `(time,)`
+5. Update `timestep_duration` to have shape `(cluster, time)` when clustered
+6. Update `aggregation_weight` computation to broadcast correctly
+
+**Files:**
+- `flixopt/flow_system.py` - Core dimension handling
+- `flixopt/clustering/base.py` - Updated Clustering class
+
+**Key Changes:**
+```python
+# FlowSystem property updates:
+@property
+def is_clustered(self) -> bool:
+ return self.clustering is not None
+
+@property
+def cluster_weight(self) -> xr.DataArray:
+ if not self.is_clustered:
+ return xr.DataArray(1.0)
+ # Shape: (cluster,) - one weight per cluster
+ return xr.DataArray(
+ self.clustering.cluster_occurrences,
+ dims=['cluster'],
+ coords={'cluster': range(self.clustering.n_clusters)}
+ )
+
+@property
+def timestep_duration(self) -> xr.DataArray:
+ if not self.is_clustered:
+ return self._timestep_duration # Shape: (time,) or scalar
+ # Shape: (cluster, time) when clustered
+ return self._timestep_duration # Already 2D from clustering
+
+@property
+def aggregation_weight(self) -> xr.DataArray:
+ return self.timestep_duration * self.cluster_weight # Broadcasting handles shapes
+```
+
+### Phase 2: Update Variable/Constraint Creation
+
+**Goal:** All variables and constraints use `(cluster, time)` dimensions when clustered.
+
+**Tasks:**
+1. Update `create_variable` to use `(cluster, time, period, scenario)` dims when clustered
+2. Update constraint generation in all models
+3. Verify linopy handles multi-dimensional constraint arrays correctly
+4. Add tests for both clustered and non-clustered paths
+
+**Files:**
+- `flixopt/core.py` - Variable creation
+- `flixopt/components.py` - StorageModel, other component models
+- `flixopt/features.py` - StatusModel, other feature models
+
+**Key Pattern:**
+```python
+# Dimension-aware variable creation:
+def _get_time_dims(self) -> list[str]:
+ if self.flow_system.is_clustered:
+ return ['cluster', 'time']
+ return ['time']
+
+def _get_time_coords(self) -> dict:
+ if self.flow_system.is_clustered:
+ return {
+ 'cluster': range(self.flow_system.clustering.n_clusters),
+ 'time': range(self.flow_system.clustering.timesteps_per_cluster)
+ }
+ return {'time': self.flow_system.time_coords}
+```
+
+### Phase 3: Simplify StorageModel and InterclusterStorageModel
+
+**Goal:** Leverage true dimensions for clean constraint generation.
+
+**Tasks:**
+1. Simplify `StorageModel.charge_balance` - no boundary masking needed
+2. Simplify delta SOC calculation: `charge_state[:, -1] - charge_state[:, 0]`
+3. Simplify `InterclusterStorageModel` linking constraints
+4. Update `intercluster_helpers.py` utilities
+
+**Files:**
+- `flixopt/components.py` - StorageModel, InterclusterStorageModel
+- `flixopt/clustering/intercluster_helpers.py` - Simplified helpers
+
+**Before/After:**
+```python
+# BEFORE (flat time with masking):
+start_positions = clustering.cluster_start_positions
+end_positions = start_positions[1:] - 1
+mask = _build_boundary_mask(...)
+balance = charge_state.isel(time=slice(1, None)).where(~mask) - ...
+
+# AFTER (true dimensions):
+# charge_state shape: (cluster, time+1, ...)
+balance = (
+ charge_state[:, 1:] -
+ charge_state[:, :-1] * (1 - loss_rate) -
+ charge * eta_charge +
+ discharge / eta_discharge
+)
+# No masking needed - constraints naturally stay within clusters!
+```
+
+### Phase 4: Update transform_accessor.cluster()
+
+**Goal:** Produce true `(cluster, time)` shaped data.
+
+**Tasks:**
+1. Update `cluster()` to reshape time series to `(cluster, time)`
+2. Generate proper coordinates for cluster dimension
+3. Update `expand_solution()` to handle reverse transformation
+4. Handle SOC_boundary expansion for inter-cluster storage
+
+**Files:**
+- `flixopt/transform_accessor.py` - cluster() and expand_solution()
+
+**Key Implementation:**
+```python
+def cluster(self, n_clusters, cluster_duration, ...):
+ """Create clustered FlowSystem with (cluster, time) dimensions."""
+ ...
+ # Reshape all time series: (flat_time,) β (cluster, time)
+ for key, ts in time_series.items():
+ reshaped = ts.values.reshape(n_clusters, timesteps_per_cluster)
+ new_ts = xr.DataArray(
+ reshaped,
+ dims=['cluster', 'time'],
+ coords={'cluster': range(n_clusters), 'time': range(timesteps_per_cluster)}
+ )
+ clustered_time_series[key] = new_ts
+ ...
+
+def expand_solution(self):
+ """Expand clustered solution back to original timeline."""
+ expanded = {}
+ for var_name, var_data in self.solution.items():
+ if 'cluster' in var_data.dims:
+ # Expand using cluster_order to map back to original periods
+ expanded[var_name] = self._expand_clustered_data(var_data)
+ else:
+ expanded[var_name] = var_data
+ return xr.Dataset(expanded)
+```
+
+### Phase 5: Plotting Integration
+
+**Goal:** Minimal changes - leverage existing infrastructure.
+
+**Tasks:**
+1. Ensure `facet_col='cluster'` works with existing plot methods
+2. Add auto cluster separators in combined time series views
+3. Test heatmaps with `(cluster, time)` data
+
+**Files:**
+- `flixopt/statistics_accessor.py` - Minor update to base plot method
+
+**Implementation:**
+```python
+# In _create_base_plot or similar:
+def _add_cluster_separators(self, fig):
+ """Add subtle separators between clusters in combined view."""
+ if self._fs.is_clustered:
+ for cluster_idx in range(1, self._fs.clustering.n_clusters):
+ x_pos = cluster_idx * self._fs.clustering.timesteps_per_cluster
+ fig.add_vline(x=x_pos, line_dash='dot', opacity=0.3)
+```
+
+### Phase Summary
+
+| Phase | Goal | Complexity | StatusModel Fix? |
+|-------|------|------------|------------------|
+| 1 | Core dimension refactoring | High | N/A (prep work) |
+| 2 | Variable/constraint creation | Medium | β
Automatic |
+| 3 | StorageModel simplification | Medium | N/A |
+| 4 | transform_accessor updates | Medium | N/A |
+| 5 | Plotting integration | Low | N/A |
+
+**Key Insight:** With true `(cluster, time)` dimensions, StatusModel and other temporal constraints **just work** without any special handling. The dimension structure naturally prevents constraints from spanning cluster boundaries.
+
+---
+
+## Part 7: Testing Strategy
+
+### 7.1 Unit Tests
+
+```python
+# Test cluster helpers
+def test_cluster_labels_uniform():
+ """Verify cluster_labels for uniform cluster lengths."""
+
+def test_cluster_slices_variable():
+ """Verify cluster_slices for variable cluster lengths."""
+
+def test_boundaries_vary_by_period():
+ """Verify boundary dispatch for different periods."""
+```
+
+### 7.2 Integration Tests
+
+```python
+# Test storage with different cluster modes
+def test_storage_intercluster_with_helpers():
+ """Verify intercluster storage using new helpers."""
+
+def test_storage_variable_boundaries():
+ """Verify storage with period-varying boundaries."""
+```
+
+### 7.3 Plotting Tests
+
+```python
+# Test new plot methods
+def test_storage_by_cluster_facets():
+ """Verify faceted cluster view."""
+
+def test_cluster_heatmap():
+ """Verify cluster heatmap rendering."""
+```
+
+---
+
+## Part 8: Decisions (Resolved)
+
+| Question | Decision |
+|----------|----------|
+| **Naming** | Use `cluster` as the dimension/coordinate name |
+| **Indexer return type** | Always return proper multi-dimensional xarray DataArrays |
+| **Segmentation** | tsam uniform segments only (sufficient for current needs) |
+| **Backwards compatibility** | Not a concern - this is not released yet |
+
+---
+
+## Appendix A: File Reference
+
+| File | Purpose |
+|------|---------|
+| `flixopt/clustering/base.py` | ClusterStructure, Clustering classes |
+| `flixopt/clustering/intercluster_helpers.py` | SOC boundary utilities |
+| `flixopt/flow_system.py` | FlowSystem with is_clustered property |
+| `flixopt/transform_accessor.py` | cluster() method, solution expansion |
+| `flixopt/components.py` | StorageModel, InterclusterStorageModel |
+| `flixopt/features.py` | StatusModel, ShareAllocationModel |
+| `flixopt/statistics_accessor.py` | Plotting methods |
+| `flixopt/plotting.py` | Plot utilities |
+
+## Appendix B: Code Examples
+
+### B.1 Working with True (cluster, time) Dimensions
+
+```python
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# DIMENSION STRUCTURE
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# Non-clustered:
+flow_rate.dims # ('time', 'period', 'scenario')
+flow_rate.shape # (8760, ...)
+
+# Clustered:
+flow_rate.dims # ('cluster', 'time', 'period', 'scenario')
+flow_rate.shape # (9, 24, ...) # 9 clusters Γ 24 timesteps
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# NATURAL CLUSTER BOUNDARY OPERATIONS
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# First/last timestep of each cluster - just use isel!
+flow_at_start = flow_rate.isel(time=0) # Shape: (cluster, period, scenario)
+flow_at_end = flow_rate.isel(time=-1) # Shape: (cluster, period, scenario)
+
+# Delta per cluster - trivial!
+delta_per_cluster = flow_rate.isel(time=-1) - flow_rate.isel(time=0)
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# TEMPORAL CONSTRAINTS - JUST WORK!
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# Storage balance - naturally stays within clusters
+balance = charge_state[:, 1:] - charge_state[:, :-1] # No masking needed!
+
+# Status transitions - naturally per cluster
+activate = status[:, 1:] - status[:, :-1] # No boundary issues!
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# PER-CLUSTER AGGREGATION - use xarray directly
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+mean_per_cluster = flow_rate.mean(dim='time') # Shape: (cluster, ...)
+max_per_cluster = flow_rate.max(dim='time')
+total_per_cluster = (flow_rate * timestep_duration).sum(dim='time')
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# SELECT SPECIFIC WITHIN-CLUSTER TIMESTEP
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# Peak hour (hour 18) from each cluster
+peak_values = flow_rate.isel(time=18) # Shape: (cluster, ...)
+
+# Multiple timesteps
+morning_values = flow_rate.isel(time=slice(6, 12)) # Hours 6-11 from each cluster
+```
+
+### B.2 Storage Constraints with True Dimensions
+
+```python
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# charge_state has one extra timestep per cluster for boundaries
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# charge_state.dims = ('cluster', 'time_cs', 'period', 'scenario')
+# charge_state.shape = (9, 25, ...) # 24 timesteps + 1 boundary
+
+# Charge balance - vectorized, no loops!
+lhs = (
+ charge_state[:, 1:] - # SOC at end of timestep
+ charge_state[:, :-1] * (1 - loss_rate) - # SOC at start, with loss
+ charge * eta_charge + # Charging adds energy
+ discharge / eta_discharge # Discharging removes energy
+)
+model.add_constraints(lhs == 0, name='charge_balance')
+
+# Delta SOC per cluster (for inter-cluster linking)
+delta_soc = charge_state[:, -1] - charge_state[:, 0] # Shape: (cluster, ...)
+
+# Cluster start constraint (relative SOC starts at 0 within each cluster)
+model.add_constraints(charge_state[:, 0] == 0, name='cluster_start')
+
+# Cyclic constraint (optional)
+model.add_constraints(
+ charge_state[:, 0] == charge_state[:, -1],
+ name='cyclic'
+)
+```
+
+### B.3 Cluster Plotting (Uses Existing API!)
+
+```python
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# FACET BY CLUSTER - uses existing facet_col parameter
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+fs.statistics.plot.storage('Battery', facet_col='cluster')
+fs.statistics.plot.balance('Heat', facet_col='cluster')
+fs.statistics.plot.flows(..., facet_col='cluster')
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# REGULAR PLOTS - auto-add cluster separators when clustered
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+fs.statistics.plot.storage('Battery') # separators added automatically
+
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+# COMBINE WITH OTHER FACETS
+# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+fs.statistics.plot.balance('Heat', facet_col='cluster', facet_row='scenario')
+```
+
+### B.4 Check Clustering Status and Access Properties
+
+```python
+if flow_system.is_clustered:
+ clustering = flow_system.clustering
+ print(f"Clustered: {clustering.n_clusters} clusters Γ {clustering.timesteps_per_cluster} timesteps")
+
+ # Dimension information
+ print(f"Data shape: (cluster={clustering.n_clusters}, time={clustering.timesteps_per_cluster})")
+
+ # Cluster weights (how many original periods each cluster represents)
+ print(f"Cluster weights: {flow_system.cluster_weight.values}")
+
+ # Aggregation weight (cluster_weight Γ timestep_duration)
+ print(f"Aggregation weight shape: {flow_system.aggregation_weight.shape}")
+else:
+ print("Not clustered - full time resolution")
+```
diff --git a/docs/notebooks/02-heat-system.ipynb b/docs/notebooks/02-heat-system.ipynb
index 3ff933ec3..d3514de15 100644
--- a/docs/notebooks/02-heat-system.ipynb
+++ b/docs/notebooks/02-heat-system.ipynb
@@ -32,9 +32,7 @@
"metadata": {},
"outputs": [],
"source": [
- "import numpy as np\n",
"import pandas as pd\n",
- "import plotly.express as px\n",
"import xarray as xr\n",
"\n",
"import flixopt as fx\n",
@@ -59,33 +57,12 @@
"metadata": {},
"outputs": [],
"source": [
- "# One week, hourly resolution\n",
- "timesteps = pd.date_range('2024-01-15', periods=168, freq='h')\n",
+ "from data.tutorial_data import get_heat_system_data\n",
"\n",
- "# Create realistic office heat demand pattern\n",
- "hours = np.arange(168)\n",
- "hour_of_day = hours % 24\n",
- "day_of_week = (hours // 24) % 7\n",
- "\n",
- "# Base demand pattern (kW)\n",
- "base_demand = np.where(\n",
- " (hour_of_day >= 7) & (hour_of_day <= 18), # Office hours\n",
- " 80, # Daytime\n",
- " 30, # Night setback\n",
- ")\n",
- "\n",
- "# Reduce on weekends (days 5, 6)\n",
- "weekend_factor = np.where(day_of_week >= 5, 0.5, 1.0)\n",
- "heat_demand = base_demand * weekend_factor\n",
- "\n",
- "# Add some random variation\n",
- "np.random.seed(42)\n",
- "heat_demand = heat_demand + np.random.normal(0, 5, len(heat_demand))\n",
- "heat_demand = np.clip(heat_demand, 20, 100)\n",
- "\n",
- "print(f'Time range: {timesteps[0]} to {timesteps[-1]}')\n",
- "print(f'Peak demand: {heat_demand.max():.1f} kW')\n",
- "print(f'Total demand: {heat_demand.sum():.0f} kWh')"
+ "data = get_heat_system_data()\n",
+ "timesteps = data['timesteps']\n",
+ "heat_demand = data['heat_demand']\n",
+ "gas_price = data['gas_price']"
]
},
{
@@ -95,15 +72,13 @@
"metadata": {},
"outputs": [],
"source": [
- "# Visualize the demand pattern with plotly\n",
- "demand_series = xr.DataArray(heat_demand, dims=['time'], coords={'time': timesteps}, name='Heat Demand [kW]')\n",
- "fig = px.line(\n",
- " x=demand_series.time.values,\n",
- " y=demand_series.values,\n",
- " title='Office Heat Demand Profile',\n",
- " labels={'x': 'Time', 'y': 'kW'},\n",
+ "# Visualize the demand pattern with fxplot\n",
+ "demand_ds = xr.Dataset(\n",
+ " {\n",
+ " 'Heat Demand': xr.DataArray(heat_demand, dims=['time'], coords={'time': timesteps}),\n",
+ " }\n",
")\n",
- "fig"
+ "demand_ds.fxplot.line(title='Office Heat Demand Profile')"
]
},
{
@@ -123,15 +98,13 @@
"metadata": {},
"outputs": [],
"source": [
- "# Time-of-use gas prices (β¬/kWh)\n",
- "gas_price = np.where(\n",
- " (hour_of_day >= 6) & (hour_of_day <= 22),\n",
- " 0.08, # Peak: 6am-10pm\n",
- " 0.05, # Off-peak: 10pm-6am\n",
+ "# Visualize time-of-use gas prices with fxplot\n",
+ "price_ds = xr.Dataset(\n",
+ " {\n",
+ " 'Gas Price': xr.DataArray(gas_price, dims=['time'], coords={'time': timesteps}),\n",
+ " }\n",
")\n",
- "\n",
- "fig = px.line(x=timesteps, y=gas_price, title='Gas Price [β¬/kWh]', labels={'x': 'Time', 'y': 'β¬/kWh'})\n",
- "fig"
+ "price_ds.fxplot.line(title='Gas Price [β¬/kWh]')"
]
},
{
@@ -309,12 +282,16 @@
"metadata": {},
"outputs": [],
"source": [
- "total_costs = flow_system.solution['costs'].item()\n",
"total_heat = heat_demand.sum()\n",
"\n",
- "print(f'Total operating costs: {total_costs:.2f} β¬')\n",
- "print(f'Total heat delivered: {total_heat:.0f} kWh')\n",
- "print(f'Average cost: {total_costs / total_heat * 100:.2f} ct/kWh')"
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'Total operating costs [EUR]': flow_system.solution['costs'].item(),\n",
+ " 'Total heat delivered [kWh]': total_heat,\n",
+ " 'Average cost [ct/kWh]': flow_system.solution['costs'].item() / total_heat * 100,\n",
+ " },\n",
+ " index=['Value'],\n",
+ ").T"
]
},
{
@@ -398,17 +375,7 @@
]
}
],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "name": "python",
- "version": "3.11"
- }
- },
+ "metadata": {},
"nbformat": 4,
"nbformat_minor": 5
}
diff --git a/docs/notebooks/03-investment-optimization.ipynb b/docs/notebooks/03-investment-optimization.ipynb
index 349c84ccf..a4ae769c5 100644
--- a/docs/notebooks/03-investment-optimization.ipynb
+++ b/docs/notebooks/03-investment-optimization.ipynb
@@ -32,9 +32,7 @@
"metadata": {},
"outputs": [],
"source": [
- "import numpy as np\n",
"import pandas as pd\n",
- "import plotly.express as px\n",
"import xarray as xr\n",
"\n",
"import flixopt as fx\n",
@@ -84,26 +82,15 @@
"metadata": {},
"outputs": [],
"source": [
- "# One week in summer, hourly\n",
- "timesteps = pd.date_range('2024-07-15', periods=168, freq='h')\n",
- "hours = np.arange(168)\n",
- "hour_of_day = hours % 24\n",
- "\n",
- "# Solar radiation profile (kW/mΒ² equivalent, simplified)\n",
- "# Peak around noon, zero at night\n",
- "solar_profile = np.maximum(0, np.sin((hour_of_day - 6) * np.pi / 12)) * 0.8\n",
- "solar_profile = np.where((hour_of_day >= 6) & (hour_of_day <= 20), solar_profile, 0)\n",
- "\n",
- "# Add some cloud variation\n",
- "np.random.seed(42)\n",
- "cloud_factor = np.random.uniform(0.6, 1.0, len(timesteps))\n",
- "solar_profile = solar_profile * cloud_factor\n",
- "\n",
- "# Pool operates 8am-10pm, constant demand when open\n",
- "pool_demand = np.where((hour_of_day >= 8) & (hour_of_day <= 22), 150, 50) # kW\n",
- "\n",
- "print(f'Peak solar: {solar_profile.max():.2f} kW/kW_installed')\n",
- "print(f'Pool demand: {pool_demand.max():.0f} kW (open), {pool_demand.min():.0f} kW (closed)')"
+ "from data.tutorial_data import get_investment_data\n",
+ "\n",
+ "data = get_investment_data()\n",
+ "timesteps = data['timesteps']\n",
+ "solar_profile = data['solar_profile']\n",
+ "pool_demand = data['pool_demand']\n",
+ "GAS_PRICE = data['gas_price']\n",
+ "SOLAR_COST_WEEKLY = data['solar_cost_per_kw_week']\n",
+ "TANK_COST_WEEKLY = data['tank_cost_per_kwh_week']"
]
},
{
@@ -113,63 +100,20 @@
"metadata": {},
"outputs": [],
"source": [
- "# Visualize profiles with plotly - using xarray and faceting\n",
+ "# Visualize profiles with fxplot\n",
"profiles = xr.Dataset(\n",
" {\n",
" 'Solar Profile [kW/kW]': xr.DataArray(solar_profile, dims=['time'], coords={'time': timesteps}),\n",
" 'Pool Demand [kW]': xr.DataArray(pool_demand, dims=['time'], coords={'time': timesteps}),\n",
" }\n",
")\n",
- "\n",
- "# Convert to long format for faceting\n",
- "df = profiles.to_dataframe().reset_index().melt(id_vars='time', var_name='variable', value_name='value')\n",
- "fig = px.line(df, x='time', y='value', facet_col='variable', height=300)\n",
- "fig.update_yaxes(matches=None, showticklabels=True)\n",
- "fig.for_each_annotation(lambda a: a.update(text=a.text.split('=')[-1]))\n",
- "fig"
+ "profiles.fxplot.line(title='Solar and Pool Profiles', height=300)"
]
},
{
"cell_type": "markdown",
"id": "7",
"metadata": {},
- "source": [
- "## Define Costs\n",
- "\n",
- "Investment costs are **annualized** (β¬/year) to compare with operating costs:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Cost parameters\n",
- "GAS_PRICE = 0.12 # β¬/kWh - high gas price makes solar attractive\n",
- "\n",
- "# Solar collectors: 400 β¬/kW installed, 20-year lifetime β ~25 β¬/kW/year annualized\n",
- "# (simplified, real calculation would include interest rate)\n",
- "SOLAR_COST_PER_KW = 20 # β¬/kW/year\n",
- "\n",
- "# Buffer tank: 50 β¬/kWh capacity, 30-year lifetime β ~2 β¬/kWh/year\n",
- "TANK_COST_PER_KWH = 1.5 # β¬/kWh/year\n",
- "\n",
- "# Scale factor: We model 1 week, but costs are annual\n",
- "# So we scale investment costs to weekly equivalent\n",
- "WEEKS_PER_YEAR = 52\n",
- "SOLAR_COST_WEEKLY = SOLAR_COST_PER_KW / WEEKS_PER_YEAR\n",
- "TANK_COST_WEEKLY = TANK_COST_PER_KWH / WEEKS_PER_YEAR\n",
- "\n",
- "print(f'Solar cost: {SOLAR_COST_WEEKLY:.3f} β¬/kW/week')\n",
- "print(f'Tank cost: {TANK_COST_WEEKLY:.4f} β¬/kWh/week')"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "9",
- "metadata": {},
"source": [
"## Build the System with Investment Options\n",
"\n",
@@ -179,7 +123,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "10",
+ "id": "8",
"metadata": {},
"outputs": [],
"source": [
@@ -250,7 +194,7 @@
},
{
"cell_type": "markdown",
- "id": "11",
+ "id": "9",
"metadata": {},
"source": [
"## Run Optimization"
@@ -259,7 +203,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "12",
+ "id": "10",
"metadata": {},
"outputs": [],
"source": [
@@ -268,7 +212,7 @@
},
{
"cell_type": "markdown",
- "id": "13",
+ "id": "11",
"metadata": {},
"source": [
"## Analyze Investment Decisions\n",
@@ -279,21 +223,26 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "14",
+ "id": "12",
"metadata": {},
"outputs": [],
"source": [
"solar_size = flow_system.statistics.sizes['SolarCollectors(Heat)'].item()\n",
"tank_size = flow_system.statistics.sizes['BufferTank'].item()\n",
"\n",
- "print(\n",
- " f'Optimal sizes: Solar {solar_size:.0f} kW, Tank {tank_size:.0f} kWh (ratio: {tank_size / solar_size:.1f} kWh/kW)'\n",
- ")"
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'Solar [kW]': solar_size,\n",
+ " 'Tank [kWh]': tank_size,\n",
+ " 'Ratio [kWh/kW]': tank_size / solar_size,\n",
+ " },\n",
+ " index=['Optimal Size'],\n",
+ ").T"
]
},
{
"cell_type": "markdown",
- "id": "15",
+ "id": "13",
"metadata": {},
"source": [
"### Visualize Sizes"
@@ -302,7 +251,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "16",
+ "id": "14",
"metadata": {},
"outputs": [],
"source": [
@@ -311,7 +260,7 @@
},
{
"cell_type": "markdown",
- "id": "17",
+ "id": "15",
"metadata": {},
"source": [
"### Cost Breakdown"
@@ -320,7 +269,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "18",
+ "id": "16",
"metadata": {},
"outputs": [],
"source": [
@@ -331,14 +280,19 @@
"tank_invest = tank_size * TANK_COST_WEEKLY\n",
"gas_costs = total_costs - solar_invest - tank_invest\n",
"\n",
- "print(\n",
- " f'Weekly costs: Solar {solar_invest:.1f}β¬ ({solar_invest / total_costs * 100:.0f}%) + Tank {tank_invest:.1f}β¬ ({tank_invest / total_costs * 100:.0f}%) + Gas {gas_costs:.1f}β¬ ({gas_costs / total_costs * 100:.0f}%) = {total_costs:.1f}β¬'\n",
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'Solar Investment': {'EUR': solar_invest, '%': solar_invest / total_costs * 100},\n",
+ " 'Tank Investment': {'EUR': tank_invest, '%': tank_invest / total_costs * 100},\n",
+ " 'Gas Costs': {'EUR': gas_costs, '%': gas_costs / total_costs * 100},\n",
+ " 'Total': {'EUR': total_costs, '%': 100.0},\n",
+ " }\n",
")"
]
},
{
"cell_type": "markdown",
- "id": "19",
+ "id": "17",
"metadata": {},
"source": [
"### System Operation"
@@ -347,7 +301,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "20",
+ "id": "18",
"metadata": {},
"outputs": [],
"source": [
@@ -357,7 +311,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "21",
+ "id": "19",
"metadata": {},
"outputs": [],
"source": [
@@ -367,7 +321,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "22",
+ "id": "20",
"metadata": {},
"outputs": [],
"source": [
@@ -376,7 +330,7 @@
},
{
"cell_type": "markdown",
- "id": "23",
+ "id": "21",
"metadata": {},
"source": [
"## Compare: What if No Solar?\n",
@@ -387,23 +341,30 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "24",
+ "id": "22",
"metadata": {},
"outputs": [],
"source": [
- "# Gas-only scenario\n",
+ "# Gas-only scenario for comparison\n",
"total_demand = pool_demand.sum()\n",
"gas_only_cost = total_demand / 0.92 * GAS_PRICE # All heat from gas boiler\n",
- "\n",
"savings = gas_only_cost - total_costs\n",
- "print(\n",
- " f'Solar saves {savings:.1f}β¬/week ({savings / gas_only_cost * 100:.0f}%) vs gas-only ({gas_only_cost:.1f}β¬) β {savings * 52:.0f}β¬/year'\n",
- ")"
+ "\n",
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'Gas-only [EUR/week]': gas_only_cost,\n",
+ " 'With Solar [EUR/week]': total_costs,\n",
+ " 'Savings [EUR/week]': savings,\n",
+ " 'Savings [%]': savings / gas_only_cost * 100,\n",
+ " 'Savings [EUR/year]': savings * 52,\n",
+ " },\n",
+ " index=['Value'],\n",
+ ").T"
]
},
{
"cell_type": "markdown",
- "id": "25",
+ "id": "23",
"metadata": {},
"source": [
"### Energy Flow Sankey\n",
@@ -414,7 +375,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "26",
+ "id": "24",
"metadata": {},
"outputs": [],
"source": [
@@ -423,7 +384,7 @@
},
{
"cell_type": "markdown",
- "id": "27",
+ "id": "25",
"metadata": {},
"source": [
"## Key Concepts\n",
@@ -463,17 +424,7 @@
]
}
],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "name": "python",
- "version": "3.11"
- }
- },
+ "metadata": {},
"nbformat": 4,
"nbformat_minor": 5
}
diff --git a/docs/notebooks/04-operational-constraints.ipynb b/docs/notebooks/04-operational-constraints.ipynb
index fbb611d1c..e55f2aded 100644
--- a/docs/notebooks/04-operational-constraints.ipynb
+++ b/docs/notebooks/04-operational-constraints.ipynb
@@ -32,9 +32,7 @@
"metadata": {},
"outputs": [],
"source": [
- "import numpy as np\n",
"import pandas as pd\n",
- "import plotly.express as px\n",
"import xarray as xr\n",
"\n",
"import flixopt as fx\n",
@@ -73,32 +71,11 @@
"metadata": {},
"outputs": [],
"source": [
- "# 3 days, hourly resolution\n",
- "timesteps = pd.date_range('2024-03-11', periods=72, freq='h')\n",
- "hours = np.arange(72)\n",
- "hour_of_day = hours % 24\n",
- "\n",
- "# Factory operates in shifts:\n",
- "# - Day shift (6am-2pm): 400 kW\n",
- "# - Evening shift (2pm-10pm): 350 kW\n",
- "# - Night (10pm-6am): 80 kW (maintenance heating only)\n",
- "\n",
- "steam_demand = np.select(\n",
- " [\n",
- " (hour_of_day >= 6) & (hour_of_day < 14), # Day shift\n",
- " (hour_of_day >= 14) & (hour_of_day < 22), # Evening shift\n",
- " ],\n",
- " [400, 350],\n",
- " default=80, # Night\n",
- ")\n",
- "\n",
- "# Add some variation\n",
- "np.random.seed(123)\n",
- "steam_demand = steam_demand + np.random.normal(0, 20, len(steam_demand))\n",
- "steam_demand = np.clip(steam_demand, 50, 450).astype(float)\n",
+ "from data.tutorial_data import get_constraints_data\n",
"\n",
- "print(f'Peak demand: {steam_demand.max():.0f} kW')\n",
- "print(f'Min demand: {steam_demand.min():.0f} kW')"
+ "data = get_constraints_data()\n",
+ "timesteps = data['timesteps']\n",
+ "steam_demand = data['steam_demand']"
]
},
{
@@ -108,7 +85,13 @@
"metadata": {},
"outputs": [],
"source": [
- "px.line(x=timesteps, y=steam_demand, title='Factory Steam Demand', labels={'x': 'Time', 'y': 'kW'})"
+ "# Visualize the demand with fxplot\n",
+ "demand_ds = xr.Dataset(\n",
+ " {\n",
+ " 'Steam Demand [kW]': xr.DataArray(steam_demand, dims=['time'], coords={'time': timesteps}),\n",
+ " }\n",
+ ")\n",
+ "demand_ds.fxplot.line(title='Factory Steam Demand')"
]
},
{
@@ -126,7 +109,7 @@
"metadata": {},
"outputs": [],
"source": [
- "flow_system = fx.FlowSystem(timesteps)\n",
+ "flow_system = fx.FlowSystem(timesteps, name='Constrained')\n",
"\n",
"# Define and register custom carriers\n",
"flow_system.add_carriers(\n",
@@ -267,11 +250,7 @@
" }\n",
")\n",
"\n",
- "df = status_ds.to_dataframe().reset_index().melt(id_vars='time', var_name='variable', value_name='value')\n",
- "fig = px.line(df, x='time', y='value', facet_col='variable', height=300, title='Main Boiler Operation')\n",
- "fig.update_yaxes(matches=None, showticklabels=True)\n",
- "fig.for_each_annotation(lambda a: a.update(text=a.text.split('=')[-1]))\n",
- "fig"
+ "status_ds.fxplot.line(title='Main Boiler Operation', height=300)"
]
},
{
@@ -294,8 +273,12 @@
"startup_costs = total_startups * 50\n",
"gas_costs = total_costs - startup_costs\n",
"\n",
- "print(\n",
- " f'{total_startups} startups Γ 50β¬ = {startup_costs:.0f}β¬ startup + {gas_costs:.0f}β¬ gas = {total_costs:.0f}β¬ total'\n",
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'Startups': {'Count': total_startups, 'EUR': startup_costs},\n",
+ " 'Gas': {'Count': '-', 'EUR': gas_costs},\n",
+ " 'Total': {'Count': '-', 'EUR': total_costs},\n",
+ " }\n",
")"
]
},
@@ -347,7 +330,7 @@
"outputs": [],
"source": [
"# Build unconstrained system\n",
- "fs_unconstrained = fx.FlowSystem(timesteps)\n",
+ "fs_unconstrained = fx.FlowSystem(timesteps, name='Unconstrained')\n",
"fs_unconstrained.add_carriers(\n",
" fx.Carrier('gas', '#3498db', 'kW'),\n",
" fx.Carrier('steam', '#87CEEB', 'kW_th', 'Process steam'),\n",
@@ -377,14 +360,43 @@
"fs_unconstrained.optimize(fx.solvers.HighsSolver())\n",
"unconstrained_costs = fs_unconstrained.solution['costs'].item()\n",
"\n",
- "constraint_overhead = (total_costs - unconstrained_costs) / unconstrained_costs * 100\n",
- "print(f'Constraints add {constraint_overhead:.1f}% cost: {unconstrained_costs:.0f}β¬ β {total_costs:.0f}β¬')"
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'Without Constraints': {'Cost [EUR]': unconstrained_costs},\n",
+ " 'With Constraints': {'Cost [EUR]': total_costs},\n",
+ " 'Overhead': {\n",
+ " 'Cost [EUR]': total_costs - unconstrained_costs,\n",
+ " '%': (total_costs - unconstrained_costs) / unconstrained_costs * 100,\n",
+ " },\n",
+ " }\n",
+ ")"
]
},
{
"cell_type": "markdown",
"id": "24",
"metadata": {},
+ "source": [
+ "### Side-by-Side Comparison\n",
+ "\n",
+ "Use the `Comparison` class to visualize both systems together:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "25",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "comp = fx.Comparison([fs_unconstrained, flow_system])\n",
+ "comp.statistics.plot.effects()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "26",
+ "metadata": {},
"source": [
"### Energy Flow Sankey\n",
"\n",
@@ -394,7 +406,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "25",
+ "id": "27",
"metadata": {},
"outputs": [],
"source": [
@@ -403,7 +415,7 @@
},
{
"cell_type": "markdown",
- "id": "26",
+ "id": "28",
"metadata": {},
"source": [
"## Key Concepts\n",
@@ -455,7 +467,13 @@
]
}
],
- "metadata": {},
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ }
+ },
"nbformat": 4,
"nbformat_minor": 5
}
diff --git a/docs/notebooks/05-multi-carrier-system.ipynb b/docs/notebooks/05-multi-carrier-system.ipynb
index a1a9543fa..1feab6e4f 100644
--- a/docs/notebooks/05-multi-carrier-system.ipynb
+++ b/docs/notebooks/05-multi-carrier-system.ipynb
@@ -32,9 +32,7 @@
"metadata": {},
"outputs": [],
"source": [
- "import numpy as np\n",
"import pandas as pd\n",
- "import plotly.express as px\n",
"import xarray as xr\n",
"\n",
"import flixopt as fx\n",
@@ -85,40 +83,15 @@
"metadata": {},
"outputs": [],
"source": [
- "# One week, hourly\n",
- "timesteps = pd.date_range('2024-02-05', periods=168, freq='h')\n",
- "hours = np.arange(168)\n",
- "hour_of_day = hours % 24\n",
- "\n",
- "# Hospital electricity demand (kW)\n",
- "# Base load + daily pattern (higher during day for equipment, lighting)\n",
- "elec_base = 150 # 24/7 critical systems\n",
- "elec_daily = 100 * np.sin((hour_of_day - 6) * np.pi / 12) # Peak at noon\n",
- "elec_daily = np.maximum(0, elec_daily)\n",
- "electricity_demand = elec_base + elec_daily\n",
- "\n",
- "# Hospital heat demand (kW)\n",
- "# Higher in morning, drops during day, increases for hot water in evening\n",
- "heat_pattern = np.select(\n",
- " [\n",
- " (hour_of_day >= 5) & (hour_of_day < 9), # Morning warmup\n",
- " (hour_of_day >= 9) & (hour_of_day < 17), # Daytime\n",
- " (hour_of_day >= 17) & (hour_of_day < 22), # Evening\n",
- " ],\n",
- " [350, 250, 300],\n",
- " default=200, # Night\n",
- ")\n",
- "heat_demand = heat_pattern.astype(float)\n",
- "\n",
- "# Add random variation\n",
- "np.random.seed(456)\n",
- "electricity_demand += np.random.normal(0, 15, len(timesteps))\n",
- "heat_demand += np.random.normal(0, 20, len(timesteps))\n",
- "electricity_demand = np.clip(electricity_demand, 100, 300)\n",
- "heat_demand = np.clip(heat_demand, 150, 400)\n",
- "\n",
- "print(f'Electricity: {electricity_demand.min():.0f} - {electricity_demand.max():.0f} kW')\n",
- "print(f'Heat: {heat_demand.min():.0f} - {heat_demand.max():.0f} kW')"
+ "from data.tutorial_data import get_multicarrier_data\n",
+ "\n",
+ "data = get_multicarrier_data()\n",
+ "timesteps = data['timesteps']\n",
+ "electricity_demand = data['electricity_demand']\n",
+ "heat_demand = data['heat_demand']\n",
+ "elec_buy_price = data['elec_buy_price']\n",
+ "elec_sell_price = data['elec_sell_price']\n",
+ "gas_price = data['gas_price']"
]
},
{
@@ -128,47 +101,20 @@
"metadata": {},
"outputs": [],
"source": [
- "# Electricity prices (β¬/kWh)\n",
- "# Time-of-use: expensive during day, cheaper at night\n",
- "elec_buy_price = np.where(\n",
- " (hour_of_day >= 7) & (hour_of_day <= 21),\n",
- " 0.35, # Peak - high electricity prices make CHP attractive\n",
- " 0.20, # Off-peak\n",
- ")\n",
- "\n",
- "# Feed-in tariff (sell price) - allows selling excess CHP electricity\n",
- "elec_sell_price = 0.12 # Fixed feed-in rate\n",
- "\n",
- "# Gas price - relatively low, favoring gas-based generation\n",
- "gas_price = 0.05 # β¬/kWh"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Visualize demands and prices with plotly - using xarray and faceting\n",
+ "# Visualize demands and prices with fxplot\n",
"profiles = xr.Dataset(\n",
" {\n",
" 'Electricity Demand [kW]': xr.DataArray(electricity_demand, dims=['time'], coords={'time': timesteps}),\n",
" 'Heat Demand [kW]': xr.DataArray(heat_demand, dims=['time'], coords={'time': timesteps}),\n",
- " 'Elec. Buy Price [β¬/kWh]': xr.DataArray(elec_buy_price, dims=['time'], coords={'time': timesteps}),\n",
+ " 'Elec. Buy Price [EUR/kWh]': xr.DataArray(elec_buy_price, dims=['time'], coords={'time': timesteps}),\n",
" }\n",
")\n",
- "\n",
- "df = profiles.to_dataframe().reset_index().melt(id_vars='time', var_name='variable', value_name='value')\n",
- "fig = px.line(df, x='time', y='value', facet_col='variable', height=300)\n",
- "fig.update_yaxes(matches=None, showticklabels=True)\n",
- "fig.for_each_annotation(lambda a: a.update(text=a.text.split('=')[-1]))\n",
- "fig"
+ "profiles.fxplot.line(title='Hospital Energy Profiles', height=300)"
]
},
{
"cell_type": "markdown",
- "id": "8",
+ "id": "7",
"metadata": {},
"source": [
"## Build the Multi-Carrier System"
@@ -177,11 +123,11 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "9",
+ "id": "8",
"metadata": {},
"outputs": [],
"source": [
- "flow_system = fx.FlowSystem(timesteps)\n",
+ "flow_system = fx.FlowSystem(timesteps, name='With CHP')\n",
"flow_system.add_carriers(\n",
" fx.Carrier('gas', '#3498db', 'kW'),\n",
" fx.Carrier('electricity', '#f1c40f', 'kW'),\n",
@@ -270,7 +216,7 @@
},
{
"cell_type": "markdown",
- "id": "10",
+ "id": "9",
"metadata": {},
"source": [
"## Run Optimization"
@@ -279,7 +225,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "11",
+ "id": "10",
"metadata": {},
"outputs": [],
"source": [
@@ -288,7 +234,7 @@
},
{
"cell_type": "markdown",
- "id": "12",
+ "id": "11",
"metadata": {},
"source": [
"## Analyze Results\n",
@@ -299,7 +245,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "13",
+ "id": "12",
"metadata": {},
"outputs": [],
"source": [
@@ -308,7 +254,7 @@
},
{
"cell_type": "markdown",
- "id": "14",
+ "id": "13",
"metadata": {},
"source": [
"### Heat Balance"
@@ -317,7 +263,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "15",
+ "id": "14",
"metadata": {},
"outputs": [],
"source": [
@@ -326,7 +272,7 @@
},
{
"cell_type": "markdown",
- "id": "16",
+ "id": "15",
"metadata": {},
"source": [
"### Gas Balance"
@@ -335,7 +281,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "17",
+ "id": "16",
"metadata": {},
"outputs": [],
"source": [
@@ -344,7 +290,7 @@
},
{
"cell_type": "markdown",
- "id": "18",
+ "id": "17",
"metadata": {},
"source": [
"### CHP Operation Pattern"
@@ -353,7 +299,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "19",
+ "id": "18",
"metadata": {},
"outputs": [],
"source": [
@@ -362,7 +308,7 @@
},
{
"cell_type": "markdown",
- "id": "20",
+ "id": "19",
"metadata": {},
"source": [
"### Cost and Emissions Summary"
@@ -371,13 +317,10 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "21",
+ "id": "20",
"metadata": {},
"outputs": [],
"source": [
- "total_costs = flow_system.solution['costs'].item()\n",
- "total_co2 = flow_system.solution['CO2'].item()\n",
- "\n",
"# Energy flows\n",
"flow_rates = flow_system.statistics.flow_rates\n",
"grid_buy = flow_rates['GridBuy(Electricity)'].sum().item()\n",
@@ -389,17 +332,25 @@
"total_elec = electricity_demand.sum()\n",
"total_heat = heat_demand.sum()\n",
"\n",
- "# Display as compact summary\n",
- "print(\n",
- " f'Electricity: {chp_elec:.0f} kWh CHP ({chp_elec / total_elec * 100:.0f}%) + {grid_buy:.0f} kWh grid, {grid_sell:.0f} kWh sold'\n",
- ")\n",
- "print(f'Heat: {chp_heat:.0f} kWh CHP ({chp_heat / total_heat * 100:.0f}%) + {boiler_heat:.0f} kWh boiler')\n",
- "print(f'Costs: {total_costs:.2f} β¬ | CO2: {total_co2:.0f} kg')"
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'CHP Electricity [kWh]': chp_elec,\n",
+ " 'CHP Electricity [%]': chp_elec / total_elec * 100,\n",
+ " 'Grid Buy [kWh]': grid_buy,\n",
+ " 'Grid Sell [kWh]': grid_sell,\n",
+ " 'CHP Heat [kWh]': chp_heat,\n",
+ " 'CHP Heat [%]': chp_heat / total_heat * 100,\n",
+ " 'Boiler Heat [kWh]': boiler_heat,\n",
+ " 'Total Costs [EUR]': flow_system.solution['costs'].item(),\n",
+ " 'Total CO2 [kg]': flow_system.solution['CO2'].item(),\n",
+ " },\n",
+ " index=['Value'],\n",
+ ").T"
]
},
{
"cell_type": "markdown",
- "id": "22",
+ "id": "21",
"metadata": {},
"source": [
"### Compare: What if No CHP?\n",
@@ -410,12 +361,12 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "23",
+ "id": "22",
"metadata": {},
"outputs": [],
"source": [
"# Build system without CHP\n",
- "fs_no_chp = fx.FlowSystem(timesteps)\n",
+ "fs_no_chp = fx.FlowSystem(timesteps, name='No CHP')\n",
"fs_no_chp.add_carriers(\n",
" fx.Carrier('gas', '#3498db', 'kW'),\n",
" fx.Carrier('electricity', '#f1c40f', 'kW'),\n",
@@ -454,20 +405,62 @@
"\n",
"fs_no_chp.optimize(fx.solvers.HighsSolver())\n",
"\n",
+ "total_costs = flow_system.solution['costs'].item()\n",
+ "total_co2 = flow_system.solution['CO2'].item()\n",
"no_chp_costs = fs_no_chp.solution['costs'].item()\n",
"no_chp_co2 = fs_no_chp.solution['CO2'].item()\n",
"\n",
- "cost_saving = (no_chp_costs - total_costs) / no_chp_costs * 100\n",
- "co2_saving = (no_chp_co2 - total_co2) / no_chp_co2 * 100\n",
- "print(\n",
- " f'CHP saves {cost_saving:.1f}% costs ({no_chp_costs:.0f}β{total_costs:.0f} β¬) and {co2_saving:.1f}% CO2 ({no_chp_co2:.0f}β{total_co2:.0f} kg)'\n",
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'Without CHP': {'Cost [EUR]': no_chp_costs, 'CO2 [kg]': no_chp_co2},\n",
+ " 'With CHP': {'Cost [EUR]': total_costs, 'CO2 [kg]': total_co2},\n",
+ " 'Savings': {\n",
+ " 'Cost [EUR]': no_chp_costs - total_costs,\n",
+ " 'CO2 [kg]': no_chp_co2 - total_co2,\n",
+ " },\n",
+ " 'Savings [%]': {\n",
+ " 'Cost [EUR]': (no_chp_costs - total_costs) / no_chp_costs * 100,\n",
+ " 'CO2 [kg]': (no_chp_co2 - total_co2) / no_chp_co2 * 100,\n",
+ " },\n",
+ " }\n",
")"
]
},
{
"cell_type": "markdown",
+ "id": "23",
+ "metadata": {},
+ "source": [
+ "### Side-by-Side Comparison\n",
+ "\n",
+ "Use the `Comparison` class to visualize both systems together:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
"id": "24",
"metadata": {},
+ "outputs": [],
+ "source": [
+ "comp = fx.Comparison([fs_no_chp, flow_system])\n",
+ "comp.statistics.plot.balance('Electricity')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "25",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "comp.statistics.plot.balance('Heat')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "26",
+ "metadata": {},
"source": [
"### Energy Flow Sankey\n",
"\n",
@@ -477,7 +470,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "25",
+ "id": "27",
"metadata": {},
"outputs": [],
"source": [
@@ -486,7 +479,7 @@
},
{
"cell_type": "markdown",
- "id": "26",
+ "id": "28",
"metadata": {},
"source": [
"## Key Concepts\n",
diff --git a/docs/notebooks/06a-time-varying-parameters.ipynb b/docs/notebooks/06a-time-varying-parameters.ipynb
index 5c833b2ea..5ebca688e 100644
--- a/docs/notebooks/06a-time-varying-parameters.ipynb
+++ b/docs/notebooks/06a-time-varying-parameters.ipynb
@@ -32,7 +32,6 @@
"outputs": [],
"source": [
"import numpy as np\n",
- "import pandas as pd\n",
"import plotly.express as px\n",
"import xarray as xr\n",
"\n",
@@ -78,20 +77,13 @@
"metadata": {},
"outputs": [],
"source": [
- "# One winter week\n",
- "timesteps = pd.date_range('2024-01-22', periods=168, freq='h')\n",
- "hours = np.arange(168)\n",
- "hour_of_day = hours % 24\n",
- "\n",
- "# Outdoor temperature: daily cycle with cold nights\n",
- "temp_base = 2 # Average temp in Β°C\n",
- "temp_amplitude = 5 # Daily variation\n",
- "outdoor_temp = temp_base + temp_amplitude * np.sin((hour_of_day - 6) * np.pi / 12)\n",
- "\n",
- "# Add day-to-day variation for realism\n",
- "np.random.seed(789)\n",
- "daily_offset = np.repeat(np.random.uniform(-3, 3, 7), 24)\n",
- "outdoor_temp = outdoor_temp + daily_offset"
+ "from data.tutorial_data import get_time_varying_data\n",
+ "\n",
+ "data = get_time_varying_data()\n",
+ "timesteps = data['timesteps']\n",
+ "outdoor_temp = data['outdoor_temp']\n",
+ "heat_demand = data['heat_demand']\n",
+ "cop = data['cop']"
]
},
{
@@ -101,74 +93,41 @@
"metadata": {},
"outputs": [],
"source": [
- "# Heat demand: inversely related to outdoor temp (higher demand when colder)\n",
- "heat_demand = 200 - 8 * outdoor_temp\n",
- "heat_demand = np.clip(heat_demand, 100, 300)"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Visualize input profiles\n",
+ "# Visualize input profiles with fxplot\n",
"profiles = xr.Dataset(\n",
" {\n",
" 'Outdoor Temp [Β°C]': xr.DataArray(outdoor_temp, dims=['time'], coords={'time': timesteps}),\n",
" 'Heat Demand [kW]': xr.DataArray(heat_demand, dims=['time'], coords={'time': timesteps}),\n",
" }\n",
")\n",
- "\n",
- "df = profiles.to_dataframe().reset_index().melt(id_vars='time', var_name='variable', value_name='value')\n",
- "fig = px.line(df, x='time', y='value', facet_col='variable', height=300)\n",
- "fig.update_yaxes(matches=None, showticklabels=True)\n",
- "fig.for_each_annotation(lambda a: a.update(text=a.text.split('=')[-1]))\n",
- "fig"
+ "profiles.fxplot.line(title='Temperature and Heat Demand Profiles', height=300)"
]
},
{
"cell_type": "markdown",
- "id": "8",
+ "id": "7",
"metadata": {},
"source": [
- "## Calculate Time-Varying COP\n",
+ "## Time-Varying COP\n",
"\n",
- "The COP depends on outdoor temperature. We use a simplified Carnot-based formula:\n",
+ "The COP is pre-calculated based on outdoor temperature using a simplified Carnot-based formula:\n",
"\n",
"$$\\text{COP}_{\\text{real}} \\approx 0.45 \\times \\text{COP}_{\\text{Carnot}} = 0.45 \\times \\frac{T_{\\text{supply}}}{T_{\\text{supply}} - T_{\\text{source}}}$$\n",
"\n",
- "where temperatures are in Kelvin."
+ "Let's visualize the relationship:"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "9",
- "metadata": {},
- "outputs": [],
- "source": [
- "# COP calculation\n",
- "T_supply = 45 + 273.15 # Supply temperature 45Β°C in Kelvin\n",
- "T_source = outdoor_temp + 273.15 # Outdoor temp in Kelvin\n",
- "\n",
- "carnot_cop = T_supply / (T_supply - T_source)\n",
- "real_cop = 0.45 * carnot_cop\n",
- "real_cop = np.clip(real_cop, 2.0, 5.0) # Physical limits"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "10",
+ "id": "8",
"metadata": {},
"outputs": [],
"source": [
"# Visualize COP vs temperature relationship\n",
"px.scatter(\n",
" x=outdoor_temp,\n",
- " y=real_cop,\n",
+ " y=cop,\n",
" title='Heat Pump COP vs Outdoor Temperature',\n",
" labels={'x': 'Outdoor Temperature [Β°C]', 'y': 'COP'},\n",
" opacity=0.5,\n",
@@ -177,7 +136,7 @@
},
{
"cell_type": "markdown",
- "id": "11",
+ "id": "9",
"metadata": {},
"source": [
"## Build the Model\n",
@@ -192,7 +151,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "12",
+ "id": "10",
"metadata": {},
"outputs": [],
"source": [
@@ -214,7 +173,7 @@
" 'HeatPump',\n",
" inputs=[fx.Flow('Elec', bus='Electricity', size=150)],\n",
" outputs=[fx.Flow('Heat', bus='Heat', size=500)],\n",
- " conversion_factors=[{'Elec': real_cop, 'Heat': 1}], # <-- Array for time-varying COP\n",
+ " conversion_factors=[{'Elec': cop, 'Heat': 1}], # <-- Array for time-varying COP\n",
" ),\n",
" # Heat demand\n",
" fx.Sink('Building', inputs=[fx.Flow('Heat', bus='Heat', size=1, fixed_relative_profile=heat_demand)]),\n",
@@ -225,7 +184,7 @@
},
{
"cell_type": "markdown",
- "id": "13",
+ "id": "11",
"metadata": {},
"source": [
"## Analyze Results"
@@ -234,7 +193,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "14",
+ "id": "12",
"metadata": {},
"outputs": [],
"source": [
@@ -244,7 +203,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "15",
+ "id": "13",
"metadata": {},
"outputs": [],
"source": [
@@ -254,7 +213,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "16",
+ "id": "14",
"metadata": {},
"outputs": [],
"source": [
@@ -283,7 +242,7 @@
},
{
"cell_type": "markdown",
- "id": "17",
+ "id": "15",
"metadata": {},
"source": [
"## Key Concepts\n",
@@ -323,7 +282,7 @@
},
{
"cell_type": "markdown",
- "id": "18",
+ "id": "16",
"metadata": {},
"source": [
"## Summary\n",
@@ -349,17 +308,7 @@
]
}
],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "name": "python",
- "version": "3.10.0"
- }
- },
+ "metadata": {},
"nbformat": 4,
"nbformat_minor": 5
}
diff --git a/docs/notebooks/07-scenarios-and-periods.ipynb b/docs/notebooks/07-scenarios-and-periods.ipynb
index db74afefb..0f3cbaef0 100644
--- a/docs/notebooks/07-scenarios-and-periods.ipynb
+++ b/docs/notebooks/07-scenarios-and-periods.ipynb
@@ -32,9 +32,8 @@
"metadata": {},
"outputs": [],
"source": [
- "import numpy as np\n",
"import pandas as pd\n",
- "import plotly.express as px\n",
+ "import xarray as xr\n",
"\n",
"import flixopt as fx\n",
"\n",
@@ -72,20 +71,16 @@
"metadata": {},
"outputs": [],
"source": [
- "# Time horizon: one representative winter week\n",
- "timesteps = pd.date_range('2024-01-15', periods=168, freq='h') # 7 days\n",
- "\n",
- "# Planning periods (years)\n",
- "periods = pd.Index([2024, 2025, 2026], name='period')\n",
- "\n",
- "# Scenarios with probabilities\n",
- "scenarios = pd.Index(['Mild Winter', 'Harsh Winter'], name='scenario')\n",
- "scenario_weights = np.array([0.6, 0.4]) # 60% mild, 40% harsh\n",
- "\n",
- "print(f'Time dimension: {len(timesteps)} hours')\n",
- "print(f'Periods: {list(periods)}')\n",
- "print(f'Scenarios: {list(scenarios)}')\n",
- "print(f'Scenario weights: {dict(zip(scenarios, scenario_weights, strict=False))}')"
+ "from data.tutorial_data import get_scenarios_data\n",
+ "\n",
+ "data = get_scenarios_data()\n",
+ "timesteps = data['timesteps']\n",
+ "periods = data['periods']\n",
+ "scenarios = data['scenarios']\n",
+ "scenario_weights = data['scenario_weights']\n",
+ "heat_demand = data['heat_demand']\n",
+ "gas_prices = data['gas_prices']\n",
+ "elec_prices = data['elec_prices']"
]
},
{
@@ -93,7 +88,7 @@
"id": "6",
"metadata": {},
"source": [
- "## Create Scenario-Dependent Demand Profiles\n",
+ "## Scenario-Dependent Demand Profiles\n",
"\n",
"Heat demand differs significantly between mild and harsh winters:"
]
@@ -105,97 +100,23 @@
"metadata": {},
"outputs": [],
"source": [
- "hours = np.arange(168)\n",
- "hour_of_day = hours % 24\n",
- "\n",
- "# Base daily pattern (kW): higher in morning/evening\n",
- "daily_pattern = np.select(\n",
- " [\n",
- " (hour_of_day >= 6) & (hour_of_day < 9), # Morning peak\n",
- " (hour_of_day >= 9) & (hour_of_day < 17), # Daytime\n",
- " (hour_of_day >= 17) & (hour_of_day < 22), # Evening peak\n",
- " ],\n",
- " [180, 120, 160],\n",
- " default=100, # Night\n",
- ").astype(float)\n",
- "\n",
- "# Add random variation\n",
- "np.random.seed(42)\n",
- "noise = np.random.normal(0, 10, len(timesteps))\n",
- "\n",
- "# Mild winter: lower demand\n",
- "mild_demand = daily_pattern * 0.8 + noise\n",
- "mild_demand = np.clip(mild_demand, 60, 200)\n",
- "\n",
- "# Harsh winter: higher demand\n",
- "harsh_demand = daily_pattern * 1.3 + noise * 1.5\n",
- "harsh_demand = np.clip(harsh_demand, 100, 280)\n",
- "\n",
- "# Create DataFrame with scenario columns (flixopt uses column names to match scenarios)\n",
- "heat_demand = pd.DataFrame(\n",
+ "# Visualize demand scenarios with fxplot\n",
+ "demand_ds = xr.Dataset(\n",
" {\n",
- " 'Mild Winter': mild_demand,\n",
- " 'Harsh Winter': harsh_demand,\n",
- " },\n",
- " index=timesteps,\n",
- ")\n",
- "\n",
- "print(f'Mild winter demand: {mild_demand.min():.0f} - {mild_demand.max():.0f} kW')\n",
- "print(f'Harsh winter demand: {harsh_demand.min():.0f} - {harsh_demand.max():.0f} kW')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "8",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Visualize demand scenarios with plotly\n",
- "fig = px.line(\n",
- " heat_demand.iloc[:48],\n",
- " title='Heat Demand by Scenario (First 2 Days)',\n",
- " labels={'index': 'Time', 'value': 'kW', 'variable': 'Scenario'},\n",
+ " scenario: xr.DataArray(\n",
+ " heat_demand[scenario].values,\n",
+ " dims=['time'],\n",
+ " coords={'time': timesteps},\n",
+ " )\n",
+ " for scenario in scenarios\n",
+ " }\n",
")\n",
- "fig.update_traces(mode='lines')\n",
- "fig"
+ "demand_ds.fxplot.line(title='Heat Demand by Scenario')"
]
},
{
"cell_type": "markdown",
- "id": "9",
- "metadata": {},
- "source": [
- "## Create Period-Dependent Prices\n",
- "\n",
- "Energy prices change across planning years:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "10",
- "metadata": {},
- "outputs": [],
- "source": [
- "# Gas prices by period (β¬/kWh) - expected to rise\n",
- "gas_prices = np.array([0.06, 0.08, 0.10]) # 2024, 2025, 2026\n",
- "\n",
- "# Electricity sell prices by period (β¬/kWh) - CHP revenue\n",
- "elec_prices = np.array([0.28, 0.34, 0.43]) # Rising with gas\n",
- "\n",
- "print('Gas prices by period:')\n",
- "for period, price in zip(periods, gas_prices, strict=False):\n",
- " print(f' {period}: {price:.2f} β¬/kWh')\n",
- "\n",
- "print('\\nElectricity sell prices by period:')\n",
- "for period, price in zip(periods, elec_prices, strict=False):\n",
- " print(f' {period}: {price:.2f} β¬/kWh')"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "11",
+ "id": "8",
"metadata": {},
"source": [
"## Build the Flow System\n",
@@ -206,7 +127,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "12",
+ "id": "9",
"metadata": {},
"outputs": [],
"source": [
@@ -215,6 +136,7 @@
" periods=periods,\n",
" scenarios=scenarios,\n",
" scenario_weights=scenario_weights,\n",
+ " name='Both Scenarios',\n",
")\n",
"flow_system.add_carriers(\n",
" fx.Carrier('gas', '#3498db', 'kW'),\n",
@@ -222,12 +144,12 @@
" fx.Carrier('heat', '#e74c3c', 'kW'),\n",
")\n",
"\n",
- "print(flow_system)"
+ "flow_system"
]
},
{
"cell_type": "markdown",
- "id": "13",
+ "id": "10",
"metadata": {},
"source": [
"## Add Components"
@@ -236,7 +158,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "14",
+ "id": "11",
"metadata": {},
"outputs": [],
"source": [
@@ -313,7 +235,7 @@
},
{
"cell_type": "markdown",
- "id": "15",
+ "id": "12",
"metadata": {},
"source": [
"## Run Optimization"
@@ -322,7 +244,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "16",
+ "id": "13",
"metadata": {},
"outputs": [],
"source": [
@@ -331,7 +253,7 @@
},
{
"cell_type": "markdown",
- "id": "17",
+ "id": "14",
"metadata": {},
"source": [
"## Analyze Results\n",
@@ -342,20 +264,25 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "18",
+ "id": "15",
"metadata": {},
"outputs": [],
"source": [
"chp_size = flow_system.statistics.sizes['CHP(P_el)']\n",
- "total_cost = flow_system.solution['costs']\n",
"\n",
- "print(f'Optimal CHP: {float(chp_size.max()):.0f} kW electrical ({float(chp_size.max()) * 0.50 / 0.35:.0f} kW thermal)')\n",
- "print(f'Expected cost: {float(total_cost.sum()):.0f} β¬')"
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'CHP Electrical [kW]': float(chp_size.max()),\n",
+ " 'CHP Thermal [kW]': float(chp_size.max()) * 0.50 / 0.35,\n",
+ " 'Expected Cost [EUR]': float(flow_system.solution['costs'].sum()),\n",
+ " },\n",
+ " index=['Optimal'],\n",
+ ").T"
]
},
{
"cell_type": "markdown",
- "id": "19",
+ "id": "16",
"metadata": {},
"source": [
"### Heat Balance by Scenario\n",
@@ -366,7 +293,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "20",
+ "id": "17",
"metadata": {},
"outputs": [],
"source": [
@@ -375,7 +302,7 @@
},
{
"cell_type": "markdown",
- "id": "21",
+ "id": "18",
"metadata": {},
"source": [
"### CHP Operation Patterns"
@@ -384,7 +311,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "22",
+ "id": "19",
"metadata": {},
"outputs": [],
"source": [
@@ -393,7 +320,7 @@
},
{
"cell_type": "markdown",
- "id": "23",
+ "id": "20",
"metadata": {},
"source": [
"### Multi-Dimensional Data Access\n",
@@ -404,13 +331,11 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "24",
+ "id": "21",
"metadata": {},
"outputs": [],
"source": [
- "# View dimensions\n",
"flow_rates = flow_system.statistics.flow_rates\n",
- "print('Flow rates dimensions:', dict(flow_rates.sizes))\n",
"\n",
"# Plot flow rates\n",
"flow_system.statistics.plot.flows()"
@@ -419,22 +344,27 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "25",
+ "id": "22",
"metadata": {},
"outputs": [],
"source": [
"# CHP operation summary by scenario\n",
"chp_heat = flow_rates['CHP(Q_th)']\n",
"\n",
- "for scenario in scenarios:\n",
- " scenario_avg = float(chp_heat.sel(scenario=scenario).mean())\n",
- " scenario_max = float(chp_heat.sel(scenario=scenario).max())\n",
- " print(f'{scenario}: avg {scenario_avg:.0f} kW, max {scenario_max:.0f} kW')"
+ "pd.DataFrame(\n",
+ " {\n",
+ " scenario: {\n",
+ " 'Avg [kW]': float(chp_heat.sel(scenario=scenario).mean()),\n",
+ " 'Max [kW]': float(chp_heat.sel(scenario=scenario).max()),\n",
+ " }\n",
+ " for scenario in scenarios\n",
+ " }\n",
+ ")"
]
},
{
"cell_type": "markdown",
- "id": "26",
+ "id": "23",
"metadata": {},
"source": [
"## Sensitivity: What if Only Mild Winter?\n",
@@ -445,7 +375,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "27",
+ "id": "24",
"metadata": {},
"outputs": [],
"source": [
@@ -456,14 +386,18 @@
"chp_size_mild = float(fs_mild.statistics.sizes['CHP(P_el)'].max())\n",
"chp_size_both = float(chp_size.max())\n",
"\n",
- "print(\n",
- " f'CHP sizing: {chp_size_mild:.0f} kW (mild only) vs {chp_size_both:.0f} kW (both scenarios) β +{chp_size_both - chp_size_mild:.0f} kW for uncertainty'\n",
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'Mild Only': {'CHP Size [kW]': chp_size_mild},\n",
+ " 'Both Scenarios': {'CHP Size [kW]': chp_size_both},\n",
+ " 'Uncertainty Buffer': {'CHP Size [kW]': chp_size_both - chp_size_mild},\n",
+ " }\n",
")"
]
},
{
"cell_type": "markdown",
- "id": "28",
+ "id": "25",
"metadata": {},
"source": [
"### Energy Flow Sankey\n",
@@ -474,7 +408,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "29",
+ "id": "26",
"metadata": {},
"outputs": [],
"source": [
@@ -483,7 +417,7 @@
},
{
"cell_type": "markdown",
- "id": "30",
+ "id": "27",
"metadata": {},
"source": [
"## Key Concepts\n",
diff --git a/docs/notebooks/08a-aggregation.ipynb b/docs/notebooks/08a-aggregation.ipynb
index d7b7576bb..e26c19223 100644
--- a/docs/notebooks/08a-aggregation.ipynb
+++ b/docs/notebooks/08a-aggregation.ipynb
@@ -12,7 +12,6 @@
"This notebook introduces:\n",
"\n",
"- **Resampling**: Reduce time resolution (e.g., hourly β 4-hourly)\n",
- "- **Clustering**: Identify typical periods (e.g., 8 representative days)\n",
"- **Two-stage optimization**: Size with reduced data, dispatch at full resolution\n",
"- **Speed vs. accuracy trade-offs**: When to use each technique"
]
@@ -35,8 +34,8 @@
"import timeit\n",
"\n",
"import pandas as pd\n",
- "import plotly.express as px\n",
- "import xarray as xr\n",
+ "import plotly.graph_objects as go\n",
+ "from plotly.subplots import make_subplots\n",
"\n",
"import flixopt as fx\n",
"\n",
@@ -48,9 +47,9 @@
"id": "3",
"metadata": {},
"source": [
- "## Load Time Series Data\n",
+ "## Create the FlowSystem\n",
"\n",
- "We use real-world district heating data at 15-minute resolution (one month):"
+ "We use a district heating system with real-world time series data (one month at 15-min resolution):"
]
},
{
@@ -60,22 +59,14 @@
"metadata": {},
"outputs": [],
"source": [
- "# Load time series data (15-min resolution)\n",
- "data = pd.read_csv('data/Zeitreihen2020.csv', index_col=0, parse_dates=True).sort_index()\n",
- "data = data['2020-01-01':'2020-01-31 23:45:00'] # One month\n",
- "data.index.name = 'time' # Rename index for consistency\n",
- "\n",
- "timesteps = data.index\n",
- "\n",
- "# Extract profiles\n",
- "electricity_demand = data['P_Netz/MW'].to_numpy()\n",
- "heat_demand = data['Q_Netz/MW'].to_numpy()\n",
- "electricity_price = data['Strompr.β¬/MWh'].to_numpy()\n",
- "gas_price = data['Gaspr.β¬/MWh'].to_numpy()\n",
- "\n",
- "print(f'Timesteps: {len(timesteps)} ({len(timesteps) / 96:.0f} days at 15-min resolution)')\n",
- "print(f'Heat demand: {heat_demand.min():.1f} - {heat_demand.max():.1f} MW')\n",
- "print(f'Electricity price: {electricity_price.min():.1f} - {electricity_price.max():.1f} β¬/MWh')"
+ "from data.generate_example_systems import create_district_heating_system\n",
+ "\n",
+ "flow_system = create_district_heating_system()\n",
+ "flow_system.connect_and_transform() # Align all data as xarray\n",
+ "\n",
+ "timesteps = flow_system.timesteps\n",
+ "print(f'Loaded FlowSystem: {len(timesteps)} timesteps ({len(timesteps) / 24:.0f} days at hourly resolution)')\n",
+ "print(f'Components: {list(flow_system.components.keys())}')"
]
},
{
@@ -85,142 +76,24 @@
"metadata": {},
"outputs": [],
"source": [
- "# Visualize first week\n",
- "profiles = xr.Dataset(\n",
- " {\n",
- " 'Heat Demand [MW]': xr.DataArray(heat_demand[:672], dims=['time'], coords={'time': timesteps[:672]}),\n",
- " 'Electricity Price [β¬/MWh]': xr.DataArray(\n",
- " electricity_price[:672], dims=['time'], coords={'time': timesteps[:672]}\n",
- " ),\n",
- " }\n",
- ")\n",
+ "# Visualize first week of data\n",
+ "heat_demand = flow_system.components['HeatDemand'].inputs[0].fixed_relative_profile\n",
+ "electricity_price = flow_system.components['GridBuy'].outputs[0].effects_per_flow_hour['costs']\n",
"\n",
- "df = profiles.to_dataframe().reset_index().melt(id_vars='time', var_name='variable', value_name='value')\n",
- "fig = px.line(df, x='time', y='value', facet_col='variable', height=300)\n",
- "fig.update_yaxes(matches=None, showticklabels=True)\n",
- "fig.for_each_annotation(lambda a: a.update(text=a.text.split('=')[-1]))\n",
- "fig"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6",
- "metadata": {},
- "source": [
- "## Build the Base FlowSystem\n",
+ "fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1)\n",
"\n",
- "A typical district heating system with investment decisions:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "7",
- "metadata": {},
- "outputs": [],
- "source": [
- "def build_system(timesteps, heat_demand, electricity_demand, electricity_price, gas_price):\n",
- " \"\"\"Build a district heating system with CHP, boiler, and storage (with investment options).\"\"\"\n",
- " fs = fx.FlowSystem(timesteps)\n",
- "\n",
- " fs.add_elements(\n",
- " # Buses\n",
- " fx.Bus('Electricity'),\n",
- " fx.Bus('Heat'),\n",
- " fx.Bus('Gas'),\n",
- " fx.Bus('Coal'),\n",
- " # Effects\n",
- " fx.Effect('costs', 'β¬', 'Total Costs', is_standard=True, is_objective=True),\n",
- " fx.Effect('CO2', 'kg', 'CO2 Emissions'),\n",
- " # CHP with investment optimization\n",
- " fx.linear_converters.CHP(\n",
- " 'CHP',\n",
- " thermal_efficiency=0.58,\n",
- " electrical_efficiency=0.22,\n",
- " electrical_flow=fx.Flow('P_el', bus='Electricity', size=200),\n",
- " thermal_flow=fx.Flow(\n",
- " 'Q_th',\n",
- " bus='Heat',\n",
- " size=fx.InvestParameters(\n",
- " minimum_size=100,\n",
- " maximum_size=300,\n",
- " effects_of_investment_per_size={'costs': 10},\n",
- " ),\n",
- " ),\n",
- " fuel_flow=fx.Flow('Q_fu', bus='Coal'),\n",
- " ),\n",
- " # Gas Boiler with investment optimization\n",
- " fx.linear_converters.Boiler(\n",
- " 'Boiler',\n",
- " thermal_efficiency=0.85,\n",
- " thermal_flow=fx.Flow(\n",
- " 'Q_th',\n",
- " bus='Heat',\n",
- " size=fx.InvestParameters(\n",
- " minimum_size=0,\n",
- " maximum_size=150,\n",
- " effects_of_investment_per_size={'costs': 5},\n",
- " ),\n",
- " ),\n",
- " fuel_flow=fx.Flow('Q_fu', bus='Gas'),\n",
- " ),\n",
- " # Thermal Storage with investment optimization\n",
- " fx.Storage(\n",
- " 'Storage',\n",
- " capacity_in_flow_hours=fx.InvestParameters(\n",
- " minimum_size=0,\n",
- " maximum_size=1000,\n",
- " effects_of_investment_per_size={'costs': 0.5},\n",
- " ),\n",
- " initial_charge_state=0,\n",
- " eta_charge=1,\n",
- " eta_discharge=1,\n",
- " relative_loss_per_hour=0.001,\n",
- " charging=fx.Flow('Charge', size=137, bus='Heat'),\n",
- " discharging=fx.Flow('Discharge', size=158, bus='Heat'),\n",
- " ),\n",
- " # Fuel sources\n",
- " fx.Source(\n",
- " 'GasGrid',\n",
- " outputs=[fx.Flow('Q_Gas', bus='Gas', size=1000, effects_per_flow_hour={'costs': gas_price, 'CO2': 0.3})],\n",
- " ),\n",
- " fx.Source(\n",
- " 'CoalSupply',\n",
- " outputs=[fx.Flow('Q_Coal', bus='Coal', size=1000, effects_per_flow_hour={'costs': 4.6, 'CO2': 0.3})],\n",
- " ),\n",
- " # Electricity grid connection\n",
- " fx.Source(\n",
- " 'GridBuy',\n",
- " outputs=[\n",
- " fx.Flow(\n",
- " 'P_el',\n",
- " bus='Electricity',\n",
- " size=1000,\n",
- " effects_per_flow_hour={'costs': electricity_price + 0.5, 'CO2': 0.3},\n",
- " )\n",
- " ],\n",
- " ),\n",
- " fx.Sink(\n",
- " 'GridSell',\n",
- " inputs=[fx.Flow('P_el', bus='Electricity', size=1000, effects_per_flow_hour=-(electricity_price - 0.5))],\n",
- " ),\n",
- " # Demands\n",
- " fx.Sink('HeatDemand', inputs=[fx.Flow('Q_th', bus='Heat', size=1, fixed_relative_profile=heat_demand)]),\n",
- " fx.Sink(\n",
- " 'ElecDemand', inputs=[fx.Flow('P_el', bus='Electricity', size=1, fixed_relative_profile=electricity_demand)]\n",
- " ),\n",
- " )\n",
- "\n",
- " return fs\n",
- "\n",
- "\n",
- "flow_system = build_system(timesteps, heat_demand, electricity_demand, electricity_price, gas_price)\n",
- "print(f'System: {len(timesteps)} timesteps')"
+ "fig.add_trace(go.Scatter(x=timesteps[:168], y=heat_demand.values[:168], name='Heat Demand'), row=1, col=1)\n",
+ "fig.add_trace(go.Scatter(x=timesteps[:168], y=electricity_price.values[:168], name='Electricity Price'), row=2, col=1)\n",
+ "\n",
+ "fig.update_layout(height=400, title='First Week of Data')\n",
+ "fig.update_yaxes(title_text='Heat Demand [MW]', row=1, col=1)\n",
+ "fig.update_yaxes(title_text='El. Price [β¬/MWh]', row=2, col=1)\n",
+ "fig.show()"
]
},
{
"cell_type": "markdown",
- "id": "8",
+ "id": "6",
"metadata": {},
"source": [
"## Technique 1: Resampling\n",
@@ -231,13 +104,13 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "9",
+ "id": "7",
"metadata": {},
"outputs": [],
"source": [
"solver = fx.solvers.HighsSolver(mip_gap=0.01)\n",
"\n",
- "# Resample from 15min to 4h resolution\n",
+ "# Resample from 15-min to 4h resolution\n",
"fs_resampled = flow_system.transform.resample('4h')\n",
"\n",
"reduction = (1 - len(fs_resampled.timesteps) / len(flow_system.timesteps)) * 100\n",
@@ -247,7 +120,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "10",
+ "id": "8",
"metadata": {},
"outputs": [],
"source": [
@@ -261,7 +134,7 @@
},
{
"cell_type": "markdown",
- "id": "11",
+ "id": "9",
"metadata": {},
"source": [
"## Technique 2: Two-Stage Optimization\n",
@@ -273,7 +146,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "12",
+ "id": "10",
"metadata": {},
"outputs": [],
"source": [
@@ -292,13 +165,14 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "13",
+ "id": "11",
"metadata": {},
"outputs": [],
"source": [
"# Stage 2: Dispatch at full resolution with fixed sizes\n",
"start = timeit.default_timer()\n",
"fs_dispatch = flow_system.transform.fix_sizes(fs_sizing.statistics.sizes)\n",
+ "fs_dispatch.name = 'Two-Stage'\n",
"fs_dispatch.optimize(solver)\n",
"time_stage2 = timeit.default_timer() - start\n",
"\n",
@@ -309,7 +183,7 @@
},
{
"cell_type": "markdown",
- "id": "14",
+ "id": "12",
"metadata": {},
"source": [
"## Technique 3: Full Optimization (Baseline)\n",
@@ -320,12 +194,13 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "15",
+ "id": "13",
"metadata": {},
"outputs": [],
"source": [
"start = timeit.default_timer()\n",
"fs_full = flow_system.copy()\n",
+ "fs_full.name = 'Full Optimization'\n",
"fs_full.optimize(solver)\n",
"time_full = timeit.default_timer() - start\n",
"\n",
@@ -334,7 +209,7 @@
},
{
"cell_type": "markdown",
- "id": "16",
+ "id": "14",
"metadata": {},
"source": [
"## Compare Results"
@@ -343,7 +218,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "17",
+ "id": "15",
"metadata": {},
"outputs": [],
"source": [
@@ -395,37 +270,29 @@
},
{
"cell_type": "markdown",
- "id": "18",
- "metadata": {},
- "source": [
- "## Visual Comparison: Heat Balance"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "19",
+ "id": "16",
"metadata": {},
- "outputs": [],
"source": [
- "# Full optimization heat balance\n",
- "fs_full.statistics.plot.balance('Heat')"
+ "## Visual Comparison: Heat Balance\n",
+ "\n",
+ "Compare the full optimization with the two-stage approach side-by-side:"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "20",
+ "id": "17",
"metadata": {},
"outputs": [],
"source": [
- "# Two-stage optimization heat balance\n",
- "fs_dispatch.statistics.plot.balance('Heat')"
+ "# Side-by-side comparison of full optimization vs two-stage\n",
+ "comp = fx.Comparison([fs_full, fs_dispatch])\n",
+ "comp.statistics.plot.balance('Heat')"
]
},
{
"cell_type": "markdown",
- "id": "21",
+ "id": "18",
"metadata": {},
"source": [
"### Energy Flow Sankey (Full Optimization)\n",
@@ -436,7 +303,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "22",
+ "id": "19",
"metadata": {},
"outputs": [],
"source": [
@@ -445,7 +312,7 @@
},
{
"cell_type": "markdown",
- "id": "23",
+ "id": "20",
"metadata": {},
"source": [
"## When to Use Each Technique\n",
@@ -485,7 +352,7 @@
},
{
"cell_type": "markdown",
- "id": "24",
+ "id": "21",
"metadata": {},
"source": [
"## Summary\n",
@@ -506,7 +373,8 @@
"\n",
"### Next Steps\n",
"\n",
- "- **[08b-Rolling Horizon](08b-rolling-horizon.ipynb)**: For operational problems without investment decisions, decompose time into sequential segments\n",
+ "- **[08b-Rolling Horizon](08b-rolling-horizon.ipynb)**: For operational problems, decompose time into sequential segments\n",
+ "- **[08c-Clustering](08c-clustering.ipynb)**: Use typical periods with the `tsam` package\n",
"\n",
"### Further Reading\n",
"\n",
@@ -517,21 +385,9 @@
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3",
+ "display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
- },
- "language_info": {
- "codemirror_mode": {
- "name": "ipython",
- "version": 3
- },
- "file_extension": ".py",
- "mimetype": "text/x-python",
- "name": "python",
- "nbconvert_exporter": "python",
- "pygments_lexer": "ipython3",
- "version": "3.11.11"
}
},
"nbformat": 4,
diff --git a/docs/notebooks/08b-rolling-horizon.ipynb b/docs/notebooks/08b-rolling-horizon.ipynb
index e9eae6d4f..90da6d2ca 100644
--- a/docs/notebooks/08b-rolling-horizon.ipynb
+++ b/docs/notebooks/08b-rolling-horizon.ipynb
@@ -51,9 +51,9 @@
"id": "3",
"metadata": {},
"source": [
- "## Load Time Series Data\n",
+ "## Create the FlowSystem\n",
"\n",
- "We use real-world district heating data at 15-minute resolution (two weeks):"
+ "We use an operational district heating system with real-world data (two weeks at 15-min resolution):"
]
},
{
@@ -63,119 +63,19 @@
"metadata": {},
"outputs": [],
"source": [
- "# Load time series data (15-min resolution)\n",
- "data = pd.read_csv('data/Zeitreihen2020.csv', index_col=0, parse_dates=True).sort_index()\n",
- "data = data['2020-01-01':'2020-01-14 23:45:00'] # Two weeks\n",
- "data.index.name = 'time' # Rename index for consistency\n",
+ "from data.generate_example_systems import create_operational_system\n",
"\n",
- "timesteps = data.index\n",
+ "flow_system = create_operational_system()\n",
+ "flow_system.connect_and_transform() # Align all data as xarray\n",
"\n",
- "# Extract profiles\n",
- "electricity_demand = data['P_Netz/MW'].to_numpy()\n",
- "heat_demand = data['Q_Netz/MW'].to_numpy()\n",
- "electricity_price = data['Strompr.β¬/MWh'].to_numpy()\n",
- "gas_price = data['Gaspr.β¬/MWh'].to_numpy()\n",
- "\n",
- "print(\n",
- " f'{len(timesteps)} timesteps ({len(timesteps) / 96:.0f} days), heat {heat_demand.min():.0f}-{heat_demand.max():.0f} MW'\n",
- ")"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "5",
- "metadata": {},
- "outputs": [],
- "source": [
- "def build_system(timesteps, heat_demand, electricity_demand, electricity_price, gas_price):\n",
- " \"\"\"Build a district heating system with CHP, boiler, and storage.\"\"\"\n",
- " fs = fx.FlowSystem(timesteps)\n",
- "\n",
- " # Effects\n",
- "\n",
- " # Buses\n",
- " fs.add_elements(\n",
- " fx.Bus('Electricity'),\n",
- " fx.Bus('Heat'),\n",
- " fx.Bus('Gas'),\n",
- " fx.Bus('Coal'),\n",
- " fx.Effect('costs', 'β¬', 'Total Costs', is_standard=True, is_objective=True),\n",
- " fx.Effect('CO2', 'kg', 'CO2 Emissions'),\n",
- " fx.linear_converters.CHP(\n",
- " 'CHP',\n",
- " thermal_efficiency=0.58,\n",
- " electrical_efficiency=0.22,\n",
- " status_parameters=fx.StatusParameters(effects_per_startup=24000),\n",
- " electrical_flow=fx.Flow('P_el', bus='Electricity', size=200),\n",
- " thermal_flow=fx.Flow('Q_th', bus='Heat', size=200),\n",
- " fuel_flow=fx.Flow('Q_fu', bus='Coal', size=288, relative_minimum=87 / 288, previous_flow_rate=100),\n",
- " ),\n",
- " fx.linear_converters.Boiler(\n",
- " 'Boiler',\n",
- " thermal_efficiency=0.85,\n",
- " thermal_flow=fx.Flow('Q_th', bus='Heat'),\n",
- " fuel_flow=fx.Flow(\n",
- " 'Q_fu',\n",
- " bus='Gas',\n",
- " size=95,\n",
- " relative_minimum=12 / 95,\n",
- " previous_flow_rate=20,\n",
- " status_parameters=fx.StatusParameters(effects_per_startup=1000),\n",
- " ),\n",
- " ),\n",
- " fx.Storage(\n",
- " 'Storage',\n",
- " capacity_in_flow_hours=684,\n",
- " initial_charge_state=137,\n",
- " minimal_final_charge_state=137,\n",
- " maximal_final_charge_state=158,\n",
- " eta_charge=1,\n",
- " eta_discharge=1,\n",
- " relative_loss_per_hour=0.001,\n",
- " prevent_simultaneous_charge_and_discharge=True,\n",
- " charging=fx.Flow('Charge', size=137, bus='Heat'),\n",
- " discharging=fx.Flow('Discharge', size=158, bus='Heat'),\n",
- " ),\n",
- " fx.Source(\n",
- " 'GasGrid',\n",
- " outputs=[fx.Flow('Q_Gas', bus='Gas', size=1000, effects_per_flow_hour={'costs': gas_price, 'CO2': 0.3})],\n",
- " ),\n",
- " fx.Source(\n",
- " 'CoalSupply',\n",
- " outputs=[fx.Flow('Q_Coal', bus='Coal', size=1000, effects_per_flow_hour={'costs': 4.6, 'CO2': 0.3})],\n",
- " ),\n",
- " fx.Source(\n",
- " 'GridBuy',\n",
- " outputs=[\n",
- " fx.Flow(\n",
- " 'P_el',\n",
- " bus='Electricity',\n",
- " size=1000,\n",
- " effects_per_flow_hour={'costs': electricity_price + 0.5, 'CO2': 0.3},\n",
- " )\n",
- " ],\n",
- " ),\n",
- " fx.Sink(\n",
- " 'GridSell',\n",
- " inputs=[fx.Flow('P_el', bus='Electricity', size=1000, effects_per_flow_hour=-(electricity_price - 0.5))],\n",
- " ),\n",
- " fx.Sink('HeatDemand', inputs=[fx.Flow('Q_th', bus='Heat', size=1, fixed_relative_profile=heat_demand)]),\n",
- " fx.Sink(\n",
- " 'ElecDemand', inputs=[fx.Flow('P_el', bus='Electricity', size=1, fixed_relative_profile=electricity_demand)]\n",
- " ),\n",
- " )\n",
- "\n",
- " return fs\n",
- "\n",
- "\n",
- "flow_system = build_system(timesteps, heat_demand, electricity_demand, electricity_price, gas_price)\n",
- "print(f'System: {len(timesteps)} timesteps')"
+ "timesteps = flow_system.timesteps\n",
+ "print(f'Loaded FlowSystem: {len(timesteps)} timesteps ({len(timesteps) / 24:.0f} days at hourly resolution)')\n",
+ "print(f'Components: {list(flow_system.components.keys())}')"
]
},
{
"cell_type": "markdown",
- "id": "6",
+ "id": "5",
"metadata": {},
"source": [
"## Full Optimization (Baseline)\n",
@@ -186,7 +86,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "7",
+ "id": "6",
"metadata": {},
"outputs": [],
"source": [
@@ -194,6 +94,7 @@
"\n",
"start = timeit.default_timer()\n",
"fs_full = flow_system.copy()\n",
+ "fs_full.name = 'Full Optimization'\n",
"fs_full.optimize(solver)\n",
"time_full = timeit.default_timer() - start\n",
"\n",
@@ -202,7 +103,7 @@
},
{
"cell_type": "markdown",
- "id": "8",
+ "id": "7",
"metadata": {},
"source": [
"## Rolling Horizon Optimization\n",
@@ -227,12 +128,13 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "9",
+ "id": "8",
"metadata": {},
"outputs": [],
"source": [
"start = timeit.default_timer()\n",
"fs_rolling = flow_system.copy()\n",
+ "fs_rolling.name = 'Rolling Horizon'\n",
"segments = fs_rolling.optimize.rolling_horizon(\n",
" solver,\n",
" horizon=192, # 2-day segments (192 timesteps at 15-min resolution)\n",
@@ -245,7 +147,7 @@
},
{
"cell_type": "markdown",
- "id": "10",
+ "id": "9",
"metadata": {},
"source": [
"## Compare Results"
@@ -254,7 +156,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "11",
+ "id": "10",
"metadata": {},
"outputs": [],
"source": [
@@ -276,35 +178,28 @@
},
{
"cell_type": "markdown",
- "id": "12",
- "metadata": {},
- "source": [
- "## Visualize: Heat Balance Comparison"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "13",
+ "id": "11",
"metadata": {},
- "outputs": [],
"source": [
- "fs_full.statistics.plot.balance('Heat').figure.update_layout(title='Heat Balance (Full)')"
+ "markdown## Visualize: Heat Balance Comparison\n",
+ "\n",
+ "Use the `Comparison` class to view both methods side-by-side:"
]
},
{
"cell_type": "code",
"execution_count": null,
- "id": "14",
+ "id": "12",
"metadata": {},
"outputs": [],
"source": [
- "fs_rolling.statistics.plot.balance('Heat').figure.update_layout(title='Heat Balance (Rolling)')"
+ "comp = fx.Comparison([fs_full, fs_rolling])\n",
+ "comp.statistics.plot.balance('Heat')"
]
},
{
"cell_type": "markdown",
- "id": "15",
+ "id": "13",
"metadata": {},
"source": [
"## Storage State Continuity\n",
@@ -315,7 +210,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "16",
+ "id": "14",
"metadata": {},
"outputs": [],
"source": [
@@ -339,7 +234,7 @@
},
{
"cell_type": "markdown",
- "id": "17",
+ "id": "15",
"metadata": {},
"source": [
"## Inspect Individual Segments\n",
@@ -350,7 +245,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "18",
+ "id": "16",
"metadata": {},
"outputs": [],
"source": [
@@ -363,7 +258,7 @@
},
{
"cell_type": "markdown",
- "id": "19",
+ "id": "17",
"metadata": {},
"source": [
"## Visualize Segment Overlaps\n",
@@ -374,7 +269,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "20",
+ "id": "18",
"metadata": {},
"outputs": [],
"source": [
@@ -391,7 +286,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "21",
+ "id": "19",
"metadata": {},
"outputs": [],
"source": [
@@ -403,7 +298,7 @@
},
{
"cell_type": "markdown",
- "id": "22",
+ "id": "20",
"metadata": {},
"source": [
"## When to Use Rolling Horizon\n",
@@ -424,7 +319,7 @@
},
{
"cell_type": "markdown",
- "id": "23",
+ "id": "21",
"metadata": {},
"source": [
"## API Reference\n",
@@ -448,7 +343,7 @@
},
{
"cell_type": "markdown",
- "id": "24",
+ "id": "22",
"metadata": {},
"source": [
"## Summary\n",
@@ -472,17 +367,7 @@
]
}
],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3",
- "language": "python",
- "name": "python3"
- },
- "language_info": {
- "name": "python",
- "version": "3.11"
- }
- },
+ "metadata": {},
"nbformat": 4,
"nbformat_minor": 5
}
diff --git a/docs/notebooks/08c-clustering.ipynb b/docs/notebooks/08c-clustering.ipynb
new file mode 100644
index 000000000..6d85e60ba
--- /dev/null
+++ b/docs/notebooks/08c-clustering.ipynb
@@ -0,0 +1,608 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# Time Series Clustering with `cluster()`\n",
+ "\n",
+ "Accelerate investment optimization using typical periods (clustering).\n",
+ "\n",
+ "This notebook demonstrates:\n",
+ "\n",
+ "- **Typical periods**: Cluster similar time segments (e.g., days) and solve only representative ones\n",
+ "- **Weighted costs**: Automatically weight operational costs by cluster occurrence\n",
+ "- **Two-stage workflow**: Fast sizing with clustering, accurate dispatch at full resolution\n",
+ "\n",
+ "!!! note \"Requirements\"\n",
+ " This notebook requires the `tsam` package: `pip install tsam`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import timeit\n",
+ "\n",
+ "import pandas as pd\n",
+ "import xarray as xr\n",
+ "\n",
+ "import flixopt as fx\n",
+ "\n",
+ "fx.CONFIG.notebook()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2",
+ "metadata": {},
+ "source": [
+ "## Create the FlowSystem\n",
+ "\n",
+ "We use a district heating system with real-world time series data (one month at 15-min resolution):"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from data.generate_example_systems import create_district_heating_system\n",
+ "\n",
+ "flow_system = create_district_heating_system()\n",
+ "flow_system.connect_and_transform()\n",
+ "\n",
+ "timesteps = flow_system.timesteps\n",
+ "\n",
+ "flow_system"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Visualize input data\n",
+ "input_ds = xr.Dataset(\n",
+ " {\n",
+ " 'Heat Demand': flow_system.components['HeatDemand'].inputs[0].fixed_relative_profile,\n",
+ " 'Electricity Price': flow_system.components['GridBuy'].outputs[0].effects_per_flow_hour['costs'],\n",
+ " }\n",
+ ")\n",
+ "input_ds.fxplot.line(facet_row='variable', title='One Month of Input Data')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5",
+ "metadata": {},
+ "source": [
+ "## Method 1: Full Optimization (Baseline)\n",
+ "\n",
+ "First, solve the complete problem with all 2976 timesteps:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "solver = fx.solvers.HighsSolver(mip_gap=0.01)\n",
+ "\n",
+ "start = timeit.default_timer()\n",
+ "fs_full = flow_system.copy()\n",
+ "fs_full.name = 'Full Optimization'\n",
+ "fs_full.optimize(solver)\n",
+ "time_full = timeit.default_timer() - start"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7",
+ "metadata": {},
+ "source": [
+ "## Method 2: Clustering with `cluster()`\n",
+ "\n",
+ "The `cluster()` method:\n",
+ "\n",
+ "1. **Clusters similar days** using the TSAM (Time Series Aggregation Module) package\n",
+ "2. **Reduces timesteps** to only typical periods (e.g., 8 typical days = 768 timesteps)\n",
+ "3. **Weights costs** by how many original days each typical day represents\n",
+ "4. **Handles storage** with configurable behavior via `storage_mode`\n",
+ "\n",
+ "!!! warning \"Peak Forcing\"\n",
+ " Always use `time_series_for_high_peaks` to ensure extreme demand days are captured.\n",
+ " Without this, clustering may miss peak periods, causing undersized components."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "start = timeit.default_timer()\n",
+ "\n",
+ "# IMPORTANT: Force inclusion of peak demand periods!\n",
+ "peak_series = ['HeatDemand(Q_th)|fixed_relative_profile']\n",
+ "\n",
+ "# Create reduced FlowSystem with 8 typical days\n",
+ "fs_clustered = flow_system.transform.cluster(\n",
+ " n_clusters=8, # 8 typical days\n",
+ " cluster_duration='1D', # Daily clustering\n",
+ " time_series_for_high_peaks=peak_series, # Capture peak demand day\n",
+ ")\n",
+ "fs_clustered.name = 'Clustered (8 days)'\n",
+ "\n",
+ "time_clustering = timeit.default_timer() - start"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Optimize the reduced system\n",
+ "start = timeit.default_timer()\n",
+ "fs_clustered.optimize(solver)\n",
+ "time_clustered = timeit.default_timer() - start"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10",
+ "metadata": {},
+ "source": [
+ "## Understanding the Clustering\n",
+ "\n",
+ "The clustering algorithm groups similar days together. Access all metadata via `fs.clustering`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Access clustering metadata directly\n",
+ "clustering = fs_clustered.clustering\n",
+ "clustering"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "12",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Show clustering info using __repr__\n",
+ "fs_clustered.clustering"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "13",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Quality metrics - how well do the clusters represent the original data?\n",
+ "# Lower RMSE/MAE = better representation\n",
+ "clustering.metrics.to_dataframe().style.format('{:.3f}')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Visual comparison: original vs clustered time series\n",
+ "clustering.plot.compare()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "15",
+ "metadata": {},
+ "source": [
+ "## Advanced Clustering Options\n",
+ "\n",
+ "The `cluster()` method exposes many parameters for fine-tuning:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "16",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Try different clustering algorithms\n",
+ "fs_kmeans = flow_system.transform.cluster(\n",
+ " n_clusters=8,\n",
+ " cluster_duration='1D',\n",
+ " cluster_method='k_means', # Alternative: 'hierarchical' (default), 'k_medoids', 'averaging'\n",
+ ")\n",
+ "\n",
+ "fs_kmeans.clustering"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Compare quality metrics between algorithms\n",
+ "pd.DataFrame(\n",
+ " {\n",
+ " 'hierarchical': fs_clustered.clustering.metrics.to_dataframe().iloc[0],\n",
+ " 'k_means': fs_kmeans.clustering.metrics.to_dataframe().iloc[0],\n",
+ " }\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "18",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Visualize cluster structure with heatmap\n",
+ "clustering.plot.heatmap()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "19",
+ "metadata": {},
+ "source": [
+ "### Manual Cluster Assignment\n",
+ "\n",
+ "When comparing design variants or performing sensitivity analysis, you often want to\n",
+ "use the **same cluster structure** across different FlowSystem configurations.\n",
+ "Use `predef_cluster_order` to ensure comparable results:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "20",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Save the cluster order from our optimized system\n",
+ "cluster_order = fs_clustered.clustering.cluster_order.values\n",
+ "\n",
+ "# Now modify the FlowSystem (e.g., increase storage capacity limits)\n",
+ "flow_system_modified = flow_system.copy()\n",
+ "flow_system_modified.components['Storage'].capacity_in_flow_hours.maximum_size = 2000 # Larger storage option\n",
+ "\n",
+ "# Cluster with the SAME cluster structure for fair comparison\n",
+ "fs_modified_clustered = flow_system_modified.transform.cluster(\n",
+ " n_clusters=8,\n",
+ " cluster_duration='1D',\n",
+ " predef_cluster_order=cluster_order, # Reuse cluster assignments\n",
+ ")\n",
+ "fs_modified_clustered.name = 'Modified (larger storage limit)'\n",
+ "\n",
+ "# Optimize the modified system\n",
+ "fs_modified_clustered.optimize(solver)\n",
+ "\n",
+ "# Compare results using Comparison class\n",
+ "fx.Comparison([fs_clustered, fs_modified_clustered])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "21",
+ "metadata": {},
+ "source": [
+ "## Method 3: Two-Stage Workflow (Recommended)\n",
+ "\n",
+ "The recommended approach for investment optimization:\n",
+ "\n",
+ "1. **Stage 1**: Fast sizing with `cluster()` \n",
+ "2. **Stage 2**: Fix sizes (with safety margin) and dispatch at full resolution\n",
+ "\n",
+ "!!! tip \"Safety Margin\"\n",
+ " Typical periods aggregate similar days, so individual days may have higher demand \n",
+ " than the typical day. Adding a 5-10% margin ensures feasibility."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "22",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Apply safety margin to sizes\n",
+ "SAFETY_MARGIN = 1.05 # 5% buffer\n",
+ "sizes_with_margin = {name: float(size.item()) * SAFETY_MARGIN for name, size in fs_clustered.statistics.sizes.items()}"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "23",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Stage 2: Fix sizes and optimize at full resolution\n",
+ "start = timeit.default_timer()\n",
+ "\n",
+ "fs_dispatch = flow_system.transform.fix_sizes(sizes_with_margin)\n",
+ "fs_dispatch.name = 'Two-Stage'\n",
+ "fs_dispatch.optimize(solver)\n",
+ "\n",
+ "time_dispatch = timeit.default_timer() - start\n",
+ "\n",
+ "# Total two-stage time\n",
+ "total_two_stage = time_clustering + time_clustered + time_dispatch"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "24",
+ "metadata": {},
+ "source": [
+ "## Compare Results"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "25",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "results = {\n",
+ " 'Full (baseline)': {\n",
+ " 'Time [s]': time_full,\n",
+ " 'Cost [β¬]': fs_full.solution['costs'].item(),\n",
+ " 'CHP': fs_full.statistics.sizes['CHP(Q_th)'].item(),\n",
+ " 'Boiler': fs_full.statistics.sizes['Boiler(Q_th)'].item(),\n",
+ " 'Storage': fs_full.statistics.sizes['Storage'].item(),\n",
+ " },\n",
+ " 'Clustered (8 days)': {\n",
+ " 'Time [s]': time_clustering + time_clustered,\n",
+ " 'Cost [β¬]': fs_clustered.solution['costs'].item(),\n",
+ " 'CHP': fs_clustered.statistics.sizes['CHP(Q_th)'].item(),\n",
+ " 'Boiler': fs_clustered.statistics.sizes['Boiler(Q_th)'].item(),\n",
+ " 'Storage': fs_clustered.statistics.sizes['Storage'].item(),\n",
+ " },\n",
+ " 'Two-Stage': {\n",
+ " 'Time [s]': total_two_stage,\n",
+ " 'Cost [β¬]': fs_dispatch.solution['costs'].item(),\n",
+ " 'CHP': sizes_with_margin['CHP(Q_th)'],\n",
+ " 'Boiler': sizes_with_margin['Boiler(Q_th)'],\n",
+ " 'Storage': sizes_with_margin['Storage'],\n",
+ " },\n",
+ "}\n",
+ "\n",
+ "comparison = pd.DataFrame(results).T\n",
+ "baseline_cost = comparison.loc['Full (baseline)', 'Cost [β¬]']\n",
+ "baseline_time = comparison.loc['Full (baseline)', 'Time [s]']\n",
+ "comparison['Cost Gap [%]'] = ((comparison['Cost [β¬]'] - baseline_cost) / abs(baseline_cost) * 100).round(2)\n",
+ "comparison['Speedup'] = (baseline_time / comparison['Time [s]']).round(1)\n",
+ "\n",
+ "comparison.style.format(\n",
+ " {\n",
+ " 'Time [s]': '{:.1f}',\n",
+ " 'Cost [β¬]': '{:,.0f}',\n",
+ " 'CHP': '{:.1f}',\n",
+ " 'Boiler': '{:.1f}',\n",
+ " 'Storage': '{:.0f}',\n",
+ " 'Cost Gap [%]': '{:.2f}',\n",
+ " 'Speedup': '{:.1f}x',\n",
+ " }\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "26",
+ "metadata": {},
+ "source": [
+ "## Expand Solution to Full Resolution\n",
+ "\n",
+ "Use `expand_solution()` to map the clustered solution back to all original timesteps.\n",
+ "This repeats the typical period values for all days belonging to that cluster:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Expand the clustered solution to full resolution\n",
+ "fs_expanded = fs_clustered.transform.expand_solution()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "28",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Compare heat production: Full vs Expanded\n",
+ "heat_flows = ['CHP(Q_th)|flow_rate', 'Boiler(Q_th)|flow_rate']\n",
+ "\n",
+ "# Create comparison dataset\n",
+ "comparison_ds = xr.Dataset(\n",
+ " {\n",
+ " name.replace('|flow_rate', ''): xr.concat(\n",
+ " [fs_full.solution[name], fs_expanded.solution[name]], dim=pd.Index(['Full', 'Expanded'], name='method')\n",
+ " )\n",
+ " for name in heat_flows\n",
+ " }\n",
+ ")\n",
+ "\n",
+ "comparison_ds.fxplot.line(facet_col='variable', color='method', title='Heat Production Comparison')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "29",
+ "metadata": {},
+ "source": [
+ "## Visualize Clustered Heat Balance"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "30",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fs_clustered.statistics.plot.storage('Storage')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "31",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fs_expanded.statistics.plot.storage('Storage')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "32",
+ "metadata": {},
+ "source": [
+ "## API Reference\n",
+ "\n",
+ "### `transform.cluster()` Parameters\n",
+ "\n",
+ "| Parameter | Type | Default | Description |\n",
+ "|-----------|------|---------|-------------|\n",
+ "| `n_clusters` | `int` | - | Number of typical periods (e.g., 8 typical days) |\n",
+ "| `cluster_duration` | `str \\| float` | - | Duration per cluster ('1D', '24h') or hours |\n",
+ "| `weights` | `dict[str, float]` | None | Optional weights for time series in clustering |\n",
+ "| `time_series_for_high_peaks` | `list[str]` | None | **Essential**: Force inclusion of peak periods |\n",
+ "| `time_series_for_low_peaks` | `list[str]` | None | Force inclusion of minimum periods |\n",
+ "| `cluster_method` | `str` | 'hierarchical' | Algorithm: 'hierarchical', 'k_means', 'k_medoids', 'k_maxoids', 'averaging' |\n",
+ "| `representation_method` | `str` | 'medoidRepresentation' | 'medoidRepresentation', 'meanRepresentation', 'distributionAndMinMaxRepresentation' |\n",
+ "| `extreme_period_method` | `str \\| None` | None | How peaks are integrated: None, 'append', 'new_cluster_center', 'replace_cluster_center' |\n",
+ "| `rescale_cluster_periods` | `bool` | True | Rescale clusters to match original means |\n",
+ "| `predef_cluster_order` | `array` | None | Manual cluster assignments |\n",
+ "| `**tsam_kwargs` | - | - | Additional tsam parameters |\n",
+ "\n",
+ "### Clustering Object Properties\n",
+ "\n",
+ "After clustering, access metadata via `fs.clustering`:\n",
+ "\n",
+ "| Property | Description |\n",
+ "|----------|-------------|\n",
+ "| `n_clusters` | Number of clusters |\n",
+ "| `n_original_clusters` | Number of original time segments (e.g., 365 days) |\n",
+ "| `timesteps_per_cluster` | Timesteps in each cluster (e.g., 24 for daily) |\n",
+ "| `cluster_order` | xr.DataArray mapping original segment β cluster ID |\n",
+ "| `occurrences` | How many original segments each cluster represents |\n",
+ "| `metrics` | xr.Dataset with RMSE, MAE per time series |\n",
+ "| `plot.compare()` | Compare original vs clustered time series |\n",
+ "| `plot.heatmap()` | Visualize cluster structure |\n",
+ "\n",
+ "### Storage Behavior\n",
+ "\n",
+ "Each `Storage` component has a `cluster_mode` parameter:\n",
+ "\n",
+ "| Mode | Description |\n",
+ "|------|-------------|\n",
+ "| `'intercluster_cyclic'` | Links storage across clusters + yearly cyclic **(default)** |\n",
+ "| `'intercluster'` | Links storage across clusters, free start/end |\n",
+ "| `'cyclic'` | Each cluster is independent but cyclic (start = end) |\n",
+ "| `'independent'` | Each cluster is independent, free start/end |\n",
+ "\n",
+ "For a detailed comparison of storage modes, see [08c2-clustering-storage-modes](08c2-clustering-storage-modes.ipynb).\n",
+ "\n",
+ "### Peak Forcing Format\n",
+ "\n",
+ "```python\n",
+ "time_series_for_high_peaks = ['ComponentName(FlowName)|fixed_relative_profile']\n",
+ "```\n",
+ "\n",
+ "### Recommended Workflow\n",
+ "\n",
+ "```python\n",
+ "# Stage 1: Fast sizing\n",
+ "fs_sizing = flow_system.transform.cluster(\n",
+ " n_clusters=8,\n",
+ " cluster_duration='1D',\n",
+ " time_series_for_high_peaks=['Demand(Flow)|fixed_relative_profile'],\n",
+ ")\n",
+ "fs_sizing.optimize(solver)\n",
+ "\n",
+ "# Apply safety margin\n",
+ "sizes = {k: v.item() * 1.05 for k, v in fs_sizing.statistics.sizes.items()}\n",
+ "\n",
+ "# Stage 2: Accurate dispatch\n",
+ "fs_dispatch = flow_system.transform.fix_sizes(sizes)\n",
+ "fs_dispatch.optimize(solver)\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "33",
+ "metadata": {},
+ "source": [
+ "## Summary\n",
+ "\n",
+ "You learned how to:\n",
+ "\n",
+ "- Use **`cluster()`** to reduce time series into typical periods\n",
+ "- Apply **peak forcing** to capture extreme demand days\n",
+ "- Use **two-stage optimization** for fast yet accurate investment decisions\n",
+ "- **Expand solutions** back to full resolution with `expand_solution()`\n",
+ "- Access **clustering metadata** via `fs.clustering` (metrics, cluster_order, occurrences)\n",
+ "- Use **advanced options** like different algorithms\n",
+ "- **Manually assign clusters** using `predef_cluster_order`\n",
+ "\n",
+ "### Key Takeaways\n",
+ "\n",
+ "1. **Always use peak forcing** (`time_series_for_high_peaks`) for demand time series\n",
+ "2. **Add safety margin** (5-10%) when fixing sizes from clustering\n",
+ "3. **Two-stage is recommended**: clustering for sizing, full resolution for dispatch\n",
+ "4. **Storage handling** is configurable via `cluster_mode`\n",
+ "5. **Check metrics** to evaluate clustering quality\n",
+ "6. **Use `predef_cluster_order`** to reproduce or define custom cluster assignments\n",
+ "\n",
+ "### Next Steps\n",
+ "\n",
+ "- **[08c2-clustering-storage-modes](08c2-clustering-storage-modes.ipynb)**: Compare storage modes using a seasonal storage system\n",
+ "- **[08d-clustering-multiperiod](08d-clustering-multiperiod.ipynb)**: Clustering with multiple periods and scenarios"
+ ]
+ }
+ ],
+ "metadata": {},
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/notebooks/08c2-clustering-storage-modes.ipynb b/docs/notebooks/08c2-clustering-storage-modes.ipynb
new file mode 100644
index 000000000..3a9ab88ad
--- /dev/null
+++ b/docs/notebooks/08c2-clustering-storage-modes.ipynb
@@ -0,0 +1,443 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# Clustering Storage Modes\n",
+ "\n",
+ "Compare different storage handling modes when clustering time series.\n",
+ "\n",
+ "This notebook demonstrates:\n",
+ "\n",
+ "- **Four storage modes**: `independent`, `cyclic`, `intercluster`, `intercluster_cyclic`\n",
+ "- **Seasonal storage**: Why inter-cluster linking matters for long-term storage\n",
+ "- **When to use each mode**: Choosing the right mode for your application\n",
+ "\n",
+ "!!! note \"Prerequisites\"\n",
+ " Read [08c-clustering](08c-clustering.ipynb) first for clustering basics."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import timeit\n",
+ "\n",
+ "import pandas as pd\n",
+ "import plotly.graph_objects as go\n",
+ "from plotly.subplots import make_subplots\n",
+ "\n",
+ "import flixopt as fx\n",
+ "\n",
+ "fx.CONFIG.notebook()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2",
+ "metadata": {},
+ "source": [
+ "## Create the Seasonal Storage System\n",
+ "\n",
+ "We use a solar thermal + seasonal pit storage system with a full year of data.\n",
+ "This is ideal for demonstrating storage modes because:\n",
+ "\n",
+ "- **Solar peaks in summer** when heat demand is low\n",
+ "- **Heat demand peaks in winter** when solar is minimal\n",
+ "- **Seasonal storage** bridges this gap by storing summer heat for winter"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from data.generate_example_systems import create_seasonal_storage_system\n",
+ "\n",
+ "flow_system = create_seasonal_storage_system()\n",
+ "flow_system.connect_and_transform() # Align all data as xarray\n",
+ "\n",
+ "timesteps = flow_system.timesteps\n",
+ "print(f'FlowSystem: {len(timesteps)} timesteps ({len(timesteps) / 24:.0f} days)')\n",
+ "print(f'Components: {list(flow_system.components.keys())}')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "4",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Visualize the seasonal patterns\n",
+ "solar_profile = flow_system.components['SolarThermal'].outputs[0].fixed_relative_profile\n",
+ "heat_demand = flow_system.components['HeatDemand'].inputs[0].fixed_relative_profile\n",
+ "\n",
+ "# Compute daily averages using xarray resample\n",
+ "solar_daily = solar_profile.resample(time='1D').mean()\n",
+ "demand_daily = heat_demand.resample(time='1D').mean()\n",
+ "\n",
+ "fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1)\n",
+ "fig.add_trace(\n",
+ " go.Scatter(x=solar_daily.time.values, y=solar_daily.values, name='Solar (daily avg)', fill='tozeroy'), row=1, col=1\n",
+ ")\n",
+ "fig.add_trace(\n",
+ " go.Scatter(x=demand_daily.time.values, y=demand_daily.values, name='Heat Demand (daily avg)', fill='tozeroy'),\n",
+ " row=2,\n",
+ " col=1,\n",
+ ")\n",
+ "fig.update_layout(height=400, title='Seasonal Mismatch: Solar vs Heat Demand')\n",
+ "fig.update_xaxes(title_text='Day of Year', row=2, col=1)\n",
+ "fig.update_yaxes(title_text='Solar Profile', row=1, col=1)\n",
+ "fig.update_yaxes(title_text='Heat Demand [MW]', row=2, col=1)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5",
+ "metadata": {},
+ "source": [
+ "## Understanding Storage Modes\n",
+ "\n",
+ "When clustering reduces a full year to typical periods (e.g., 12 typical days), we need to\n",
+ "decide how storage behaves across these periods. Each `Storage` component has a \n",
+ "`cluster_storage_mode` parameter with four options:\n",
+ "\n",
+ "| Mode | Description | Use Case |\n",
+ "|------|-------------|----------|\n",
+ "| `'intercluster_cyclic'` | Links storage across clusters + yearly cyclic | **Default**. Seasonal storage, yearly optimization |\n",
+ "| `'intercluster'` | Links storage across clusters, free start/end | Multi-year optimization, flexible boundaries |\n",
+ "| `'cyclic'` | Each cluster independent, but cyclic (start = end) | Daily storage only, no seasonal effects |\n",
+ "| `'independent'` | Each cluster independent, free start/end | Fastest solve, ignores long-term storage |\n",
+ "\n",
+ "Let's compare them!"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6",
+ "metadata": {},
+ "source": [
+ "## Baseline: Full Year Optimization\n",
+ "\n",
+ "First, optimize the full system to establish a baseline:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "solver = fx.solvers.HighsSolver(mip_gap=0.02)\n",
+ "\n",
+ "start = timeit.default_timer()\n",
+ "fs_full = flow_system.copy()\n",
+ "fs_full.name = 'Full Optimization'\n",
+ "fs_full.optimize(solver)\n",
+ "time_full = timeit.default_timer() - start\n",
+ "\n",
+ "print(f'Full optimization: {time_full:.1f} seconds')\n",
+ "print(f'Total cost: {fs_full.solution[\"costs\"].item():,.0f} EUR')\n",
+ "print('\\nOptimized sizes:')\n",
+ "for name, size in fs_full.statistics.sizes.items():\n",
+ " print(f' {name}: {float(size.item()):.2f}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8",
+ "metadata": {},
+ "source": [
+ "## Compare Storage Modes\n",
+ "\n",
+ "Now let's cluster with each storage mode and compare results.\n",
+ "We set `cluster_storage_mode` on the Storage component before calling `cluster()`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Clustering parameters\n",
+ "N_CLUSTERS = 24 # 12 typical days for a full year\n",
+ "CLUSTER_DURATION = '1D'\n",
+ "PEAK_SERIES = ['HeatDemand(Q_th)|fixed_relative_profile']\n",
+ "\n",
+ "# Storage modes to compare\n",
+ "storage_modes = ['independent', 'cyclic', 'intercluster', 'intercluster_cyclic']\n",
+ "\n",
+ "results = {}\n",
+ "clustered_systems = {}\n",
+ "\n",
+ "for mode in storage_modes:\n",
+ " print(f'\\n--- Mode: {mode} ---')\n",
+ "\n",
+ " # Create a copy and set the storage mode\n",
+ " fs_copy = flow_system.copy()\n",
+ " fs_copy.storages['SeasonalStorage'].cluster_mode = mode\n",
+ "\n",
+ " start = timeit.default_timer()\n",
+ " fs_clustered = fs_copy.transform.cluster(\n",
+ " n_clusters=N_CLUSTERS,\n",
+ " cluster_duration=CLUSTER_DURATION,\n",
+ " time_series_for_high_peaks=PEAK_SERIES,\n",
+ " )\n",
+ " time_cluster = timeit.default_timer() - start\n",
+ "\n",
+ " start = timeit.default_timer()\n",
+ " fs_clustered.optimize(solver)\n",
+ " time_solve = timeit.default_timer() - start\n",
+ "\n",
+ " clustered_systems[mode] = fs_clustered\n",
+ "\n",
+ " results[mode] = {\n",
+ " 'Time [s]': time_cluster + time_solve,\n",
+ " 'Cost [EUR]': fs_clustered.solution['costs'].item(),\n",
+ " 'Solar [MW]': fs_clustered.statistics.sizes.get('SolarThermal(Q_th)', 0),\n",
+ " 'Boiler [MW]': fs_clustered.statistics.sizes.get('GasBoiler(Q_th)', 0),\n",
+ " 'Storage [MWh]': fs_clustered.statistics.sizes.get('SeasonalStorage', 0),\n",
+ " }\n",
+ "\n",
+ " # Handle xarray types\n",
+ " for key in ['Solar [MW]', 'Boiler [MW]', 'Storage [MWh]']:\n",
+ " val = results[mode][key]\n",
+ " results[mode][key] = float(val.item()) if hasattr(val, 'item') else float(val)\n",
+ "\n",
+ " print(f' Time: {results[mode][\"Time [s]\"]:.1f}s')\n",
+ " print(f' Cost: {results[mode][\"Cost [EUR]\"]:,.0f} EUR')\n",
+ " print(f' Storage: {results[mode][\"Storage [MWh]\"]:.0f} MWh')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "10",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Add full optimization result for comparison\n",
+ "results['Full (baseline)'] = {\n",
+ " 'Time [s]': time_full,\n",
+ " 'Cost [EUR]': fs_full.solution['costs'].item(),\n",
+ " 'Solar [MW]': float(fs_full.statistics.sizes.get('SolarThermal(Q_th)', 0).item()),\n",
+ " 'Boiler [MW]': float(fs_full.statistics.sizes.get('GasBoiler(Q_th)', 0).item()),\n",
+ " 'Storage [MWh]': float(fs_full.statistics.sizes.get('SeasonalStorage', 0).item()),\n",
+ "}\n",
+ "\n",
+ "# Create comparison DataFrame\n",
+ "comparison = pd.DataFrame(results).T\n",
+ "baseline_cost = comparison.loc['Full (baseline)', 'Cost [EUR]']\n",
+ "baseline_time = comparison.loc['Full (baseline)', 'Time [s]']\n",
+ "comparison['Cost Gap [%]'] = (comparison['Cost [EUR]'] - baseline_cost) / abs(baseline_cost) * 100\n",
+ "comparison['Speedup'] = baseline_time / comparison['Time [s]']\n",
+ "\n",
+ "comparison.style.format(\n",
+ " {\n",
+ " 'Time [s]': '{:.1f}',\n",
+ " 'Cost [EUR]': '{:,.0f}',\n",
+ " 'Solar [MW]': '{:.1f}',\n",
+ " 'Boiler [MW]': '{:.1f}',\n",
+ " 'Storage [MWh]': '{:.0f}',\n",
+ " 'Cost Gap [%]': '{:+.1f}',\n",
+ " 'Speedup': '{:.1f}x',\n",
+ " }\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "11",
+ "metadata": {},
+ "source": [
+ "## Visualize Storage Behavior\n",
+ "\n",
+ "The key difference between modes is how storage is utilized across the year.\n",
+ "Let's expand each solution back to full resolution and compare:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "12",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Expand clustered solutions to full resolution\n",
+ "expanded_systems = {}\n",
+ "for mode in storage_modes:\n",
+ " fs_expanded = clustered_systems[mode].transform.expand_solution()\n",
+ " fs_expanded.name = f'Mode: {mode}'\n",
+ " expanded_systems[mode] = fs_expanded"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "13",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Plot storage charge state for each mode\n",
+ "fig = make_subplots(\n",
+ " rows=len(storage_modes) + 1,\n",
+ " cols=1,\n",
+ " shared_xaxes=True,\n",
+ " vertical_spacing=0.05,\n",
+ " subplot_titles=['Full Optimization'] + [f'Mode: {m}' for m in storage_modes],\n",
+ ")\n",
+ "\n",
+ "# Full optimization\n",
+ "soc_full = fs_full.solution['SeasonalStorage|charge_state']\n",
+ "fig.add_trace(go.Scatter(x=fs_full.timesteps, y=soc_full.values, name='Full', line=dict(width=0.8)), row=1, col=1)\n",
+ "\n",
+ "# Expanded clustered solutions\n",
+ "for i, mode in enumerate(storage_modes, start=2):\n",
+ " fs_exp = expanded_systems[mode]\n",
+ " soc = fs_exp.solution['SeasonalStorage|charge_state']\n",
+ " fig.add_trace(go.Scatter(x=fs_exp.timesteps, y=soc.values, name=mode, line=dict(width=0.8)), row=i, col=1)\n",
+ "\n",
+ "fig.update_layout(height=800, title='Storage Charge State by Mode', showlegend=False)\n",
+ "for i in range(1, len(storage_modes) + 2):\n",
+ " fig.update_yaxes(title_text='SOC [MWh]', row=i, col=1)\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "14",
+ "metadata": {},
+ "source": [
+ "### Side-by-Side Comparison\n",
+ "\n",
+ "Use the `Comparison` class to compare the full optimization with the recommended mode:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "15",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Compare full optimization with the recommended intercluster_cyclic mode\n",
+ "comp = fx.Comparison([fs_full, expanded_systems['intercluster_cyclic']])\n",
+ "comp.statistics.plot.balance('Heat')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "16",
+ "metadata": {},
+ "source": [
+ "## Interpretation\n",
+ "\n",
+ "### `'independent'` Mode\n",
+ "- Each typical period is solved independently\n",
+ "- Storage starts and ends at arbitrary states within each cluster\n",
+ "- **No seasonal storage benefit captured** - storage is only used for daily fluctuations\n",
+ "- Fastest to solve but least accurate for seasonal systems\n",
+ "\n",
+ "### `'cyclic'` Mode \n",
+ "- Each cluster is independent but enforces start = end state\n",
+ "- Better than independent but still **no cross-season linking**\n",
+ "- Good for systems where storage only balances within-day variations\n",
+ "\n",
+ "### `'intercluster'` Mode\n",
+ "- Links storage state across the original time series via typical periods\n",
+ "- **Captures seasonal storage behavior** - summer charging, winter discharging\n",
+ "- Free start and end states (useful for multi-year optimization)\n",
+ "\n",
+ "### `'intercluster_cyclic'` Mode (Default)\n",
+ "- Inter-cluster linking **plus** yearly cyclic constraint (end = start)\n",
+ "- **Best for yearly investment optimization** with seasonal storage\n",
+ "- Ensures the storage cycle is sustainable year after year"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "17",
+ "metadata": {},
+ "source": [
+ "## When to Use Each Mode\n",
+ "\n",
+ "| Your System Has... | Recommended Mode |\n",
+ "|-------------------|------------------|\n",
+ "| Seasonal storage (pit, underground) | `'intercluster_cyclic'` |\n",
+ "| Only daily storage (batteries, hot water tanks) | `'cyclic'` |\n",
+ "| Multi-year optimization with inter-annual storage | `'intercluster'` |\n",
+ "| Quick sizing estimate, storage not critical | `'independent'` |\n",
+ "\n",
+ "### Setting the Mode\n",
+ "\n",
+ "```python\n",
+ "# Option 1: Set when creating the Storage\n",
+ "storage = fx.Storage(\n",
+ " 'SeasonalStorage',\n",
+ " capacity_in_flow_hours=5000,\n",
+ " cluster_storage_mode='intercluster_cyclic', # default\n",
+ " ...\n",
+ ")\n",
+ "\n",
+ "# Option 2: Modify before clustering\n",
+ "flow_system.components['SeasonalStorage'].cluster_storage_mode = 'cyclic'\n",
+ "fs_clustered = flow_system.transform.cluster(...)\n",
+ "```\n",
+ "\n",
+ "!!! tip \"Rule of Thumb\"\n",
+ " Use `'intercluster_cyclic'` (default) unless you have a specific reason not to.\n",
+ " It provides the most accurate representation of storage behavior in clustered systems."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "18",
+ "metadata": {},
+ "source": [
+ "## Summary\n",
+ "\n",
+ "You learned how to:\n",
+ "\n",
+ "- Use **`cluster_storage_mode`** on Storage components to control behavior in clustering\n",
+ "- Understand the **difference between modes** and their impact on results\n",
+ "- Choose the **right mode** for your optimization problem\n",
+ "\n",
+ "### Key Takeaways\n",
+ "\n",
+ "1. **Seasonal storage requires inter-cluster linking** to capture charging/discharging across seasons\n",
+ "2. **`'intercluster_cyclic'`** is the default and best for yearly investment optimization\n",
+ "3. **`'independent'` and `'cyclic'`** are faster but miss long-term storage value\n",
+ "4. **Expand solutions** with `expand_solution()` to visualize storage behavior across the year\n",
+ "\n",
+ "### Next Steps\n",
+ "\n",
+ "- **[08d-clustering-multiperiod](08d-clustering-multiperiod.ipynb)**: Clustering with multiple periods and scenarios"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.12.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/notebooks/08d-clustering-multiperiod.ipynb b/docs/notebooks/08d-clustering-multiperiod.ipynb
new file mode 100644
index 000000000..e599384ac
--- /dev/null
+++ b/docs/notebooks/08d-clustering-multiperiod.ipynb
@@ -0,0 +1,588 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# Multi-Period Clustering with `cluster()`\n",
+ "\n",
+ "Combine time series clustering with multi-period investment optimization.\n",
+ "\n",
+ "This notebook demonstrates:\n",
+ "\n",
+ "- **Multi-period modeling**: Optimize investments across multiple planning periods (years)\n",
+ "- **Scenario analysis**: Handle demand uncertainty with weighted scenarios\n",
+ "- **Clustering per period**: Apply typical-period clustering independently for each period/scenario\n",
+ "- **Scalability**: Reduce computational complexity for long-horizon planning\n",
+ "\n",
+ "!!! note \"Requirements\"\n",
+ " This notebook requires the `tsam` package: `pip install tsam`"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import timeit\n",
+ "\n",
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import plotly.express as px\n",
+ "\n",
+ "import flixopt as fx\n",
+ "\n",
+ "fx.CONFIG.notebook()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2",
+ "metadata": {},
+ "source": [
+ "## Create the Multi-Period System\n",
+ "\n",
+ "We use a multi-period heating system with:\n",
+ "- **3 planning periods** (years 2024, 2025, 2026)\n",
+ "- **2 scenarios** (high demand 30%, low demand 70%)\n",
+ "- **2 weeks** at hourly resolution (336 timesteps)\n",
+ "\n",
+ "This represents a capacity expansion problem where we optimize component sizes once,\n",
+ "but operations are simulated across multiple future years and demand scenarios."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from data.generate_example_systems import create_multiperiod_system\n",
+ "\n",
+ "flow_system = create_multiperiod_system()\n",
+ "\n",
+ "print(f'Timesteps: {len(flow_system.timesteps)} ({len(flow_system.timesteps) // 24} days)')\n",
+ "print(f'Periods: {list(flow_system.periods.values)}')\n",
+ "print(f'Scenarios: {list(flow_system.scenarios.values)}')\n",
+ "print(f'Scenario weights: {flow_system.scenario_weights.values}')\n",
+ "print(f'\\nComponents: {list(flow_system.components.keys())}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4",
+ "metadata": {},
+ "source": [
+ "## Selecting a Subset with `transform.isel()`\n",
+ "\n",
+ "For demonstration purposes, we'll use only the first week of data.\n",
+ "The `isel()` method (index select) lets you slice FlowSystems by time:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Select first week only (168 hours)\n",
+ "flow_system = flow_system.transform.isel(time=slice(0, 168))\n",
+ "\n",
+ "print(f'After isel: {len(flow_system.timesteps)} timesteps ({len(flow_system.timesteps) // 24} days)')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Visualize demand scenarios\n",
+ "heat_demand = flow_system.components['Building'].inputs[0].fixed_relative_profile\n",
+ "\n",
+ "fig = px.line(\n",
+ " heat_demand.to_dataframe('value').reset_index(), x='time', y='value', facet_col='period', facet_row='scenario'\n",
+ ")\n",
+ "\n",
+ "fig.update_layout(\n",
+ " height=350,\n",
+ " title='Heat Demand by Scenario (One Week)',\n",
+ " xaxis_title='Time',\n",
+ " yaxis_title='Heat Demand [kW]',\n",
+ ")\n",
+ "fig.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7",
+ "metadata": {},
+ "source": [
+ "## Full Optimization (Baseline)\n",
+ "\n",
+ "First, solve the complete problem with all timesteps across all periods and scenarios:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "solver = fx.solvers.HighsSolver(mip_gap=0.01)\n",
+ "\n",
+ "start = timeit.default_timer()\n",
+ "fs_full = flow_system.copy()\n",
+ "fs_full.name = 'Full Optimization'\n",
+ "fs_full.optimize(solver)\n",
+ "time_full = timeit.default_timer() - start\n",
+ "\n",
+ "print(f'Full optimization: {time_full:.2f} seconds')\n",
+ "print(f'Total cost (objective): {fs_full.solution[\"objective\"].item():,.0f} β¬')\n",
+ "print('\\nOptimized sizes:')\n",
+ "for name, size in fs_full.statistics.sizes.items():\n",
+ " print(f' {name}: {size.max().item():.1f}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9",
+ "metadata": {},
+ "source": [
+ "## Multi-Period Clustering with `cluster()`\n",
+ "\n",
+ "When applied to a multi-period system, `cluster()` clusters **each period/scenario combination independently**.\n",
+ "This is because demand patterns and optimal operations may differ across:\n",
+ "\n",
+ "- **Periods**: Different years may have different characteristics\n",
+ "- **Scenarios**: High vs low demand scenarios need different representative days\n",
+ "\n",
+ "The investment decisions (sizes) remain consistent across all periods and scenarios,\n",
+ "while the operational patterns are optimized for each cluster."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "10",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "start = timeit.default_timer()\n",
+ "\n",
+ "# Force inclusion of peak demand periods\n",
+ "peak_series = ['Building(Heat)|fixed_relative_profile']\n",
+ "\n",
+ "# Cluster to 3 typical days (from 7 days)\n",
+ "fs_clustered = flow_system.transform.cluster(\n",
+ " n_clusters=3,\n",
+ " cluster_duration='1D',\n",
+ " time_series_for_high_peaks=peak_series,\n",
+ ")\n",
+ "\n",
+ "time_clustering = timeit.default_timer() - start\n",
+ "\n",
+ "print(f'Clustering time: {time_clustering:.2f} seconds')\n",
+ "print(f'Reduced: {len(flow_system.timesteps)} β {len(fs_clustered.timesteps)} timesteps per period')\n",
+ "print('Total problem reduction: 7 days Γ 3 periods Γ 2 scenarios β 3 days Γ 3 Γ 2')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Optimize the reduced system\n",
+ "start = timeit.default_timer()\n",
+ "fs_clustered.optimize(solver)\n",
+ "time_clustered = timeit.default_timer() - start\n",
+ "\n",
+ "print(f'Clustered optimization: {time_clustered:.2f} seconds')\n",
+ "print(f'Total cost (objective): {fs_clustered.solution[\"objective\"].item():,.0f} β¬')\n",
+ "print(f'\\nSpeedup vs full: {time_full / (time_clustering + time_clustered):.1f}x')\n",
+ "print('\\nOptimized sizes:')\n",
+ "for name, size in fs_clustered.statistics.sizes.items():\n",
+ " print(f' {name}: {size.max().item():.1f}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "12",
+ "metadata": {},
+ "source": [
+ "## Visualize Clustering Quality\n",
+ "\n",
+ "The `.plot` accessor provides built-in visualizations with automatic faceting by period and scenario:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "13",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Compare original vs aggregated data - automatically faceted by period and scenario\n",
+ "fs_clustered.clustering.plot.compare(variables='Building(Heat)|fixed_relative_profile')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Duration curves show how well the distribution is preserved per period/scenario\n",
+ "fs_clustered.clustering.plot.compare(\n",
+ " kind='duration_curve',\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "15",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Heatmap shows cluster assignments - faceted by period and scenario\n",
+ "fs_clustered.clustering.plot.heatmap()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "16",
+ "metadata": {},
+ "source": [
+ "## Understand the Cluster Structure\n",
+ "\n",
+ "Let's inspect how days were grouped into clusters:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "info = fs_clustered.clustering\n",
+ "cs = info.result.cluster_structure\n",
+ "\n",
+ "print('Clustering Configuration:')\n",
+ "print(f' Typical periods (clusters): {cs.n_clusters}')\n",
+ "print(f' Timesteps per cluster: {cs.timesteps_per_cluster}')\n",
+ "\n",
+ "# The cluster_order shows which cluster each original day belongs to\n",
+ "cluster_order = cs.cluster_order.values\n",
+ "day_names = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']\n",
+ "\n",
+ "print('\\nCluster assignments per day:')\n",
+ "for i, cluster_id in enumerate(cluster_order):\n",
+ " print(f' {day_names[i]}: Cluster {cluster_id}')\n",
+ "\n",
+ "# Cluster occurrences (how many original days each cluster represents)\n",
+ "unique, counts = np.unique(cluster_order, return_counts=True)\n",
+ "print('\\nCluster weights (days represented):')\n",
+ "for cluster_id, count in zip(unique, counts, strict=False):\n",
+ " print(f' Cluster {cluster_id}: {count} days')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "18",
+ "metadata": {},
+ "source": [
+ "## Two-Stage Workflow for Multi-Period\n",
+ "\n",
+ "For investment optimization across multiple periods, the recommended workflow is:\n",
+ "\n",
+ "1. **Stage 1**: Fast sizing with clustering (reduced timesteps)\n",
+ "2. **Stage 2**: Fix sizes and run full-resolution dispatch\n",
+ "\n",
+ "This gives accurate investment decisions while maintaining computational tractability."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "19",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Stage 1 already done - apply safety margin\n",
+ "SAFETY_MARGIN = 1.10 # 10% buffer for multi-period uncertainty\n",
+ "\n",
+ "sizes_with_margin = {name: size.max().item() * SAFETY_MARGIN for name, size in fs_clustered.statistics.sizes.items()}\n",
+ "\n",
+ "print('Stage 1: Sizing with clustering')\n",
+ "print(f' Time: {time_clustering + time_clustered:.2f} seconds')\n",
+ "print(f' Cost estimate: {fs_clustered.solution[\"objective\"].item():,.0f} β¬')\n",
+ "print(f'\\nSizes with {(SAFETY_MARGIN - 1) * 100:.0f}% safety margin:')\n",
+ "for name, size in sizes_with_margin.items():\n",
+ " original = fs_clustered.statistics.sizes[name].max().item()\n",
+ " print(f' {name}: {original:.1f} β {size:.1f}')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "20",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Stage 2: Full resolution dispatch with fixed sizes\n",
+ "print('Stage 2: Full resolution dispatch')\n",
+ "start = timeit.default_timer()\n",
+ "\n",
+ "fs_dispatch = flow_system.transform.fix_sizes(sizes_with_margin)\n",
+ "fs_dispatch.name = 'Two-Stage'\n",
+ "fs_dispatch.optimize(solver)\n",
+ "\n",
+ "time_dispatch = timeit.default_timer() - start\n",
+ "\n",
+ "print(f' Time: {time_dispatch:.2f} seconds')\n",
+ "print(f' Actual cost: {fs_dispatch.solution[\"objective\"].item():,.0f} β¬')\n",
+ "\n",
+ "# Total comparison\n",
+ "total_two_stage = time_clustering + time_clustered + time_dispatch\n",
+ "print(f'\\nTotal two-stage time: {total_two_stage:.2f} seconds')\n",
+ "print(f'Speedup vs full: {time_full / total_two_stage:.1f}x')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "21",
+ "metadata": {},
+ "source": [
+ "## Compare Results Across Methods"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "22",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "results = {\n",
+ " 'Full (baseline)': {\n",
+ " 'Time [s]': time_full,\n",
+ " 'Cost [β¬]': fs_full.solution['objective'].item(),\n",
+ " 'Boiler': fs_full.statistics.sizes['Boiler(Heat)'].max().item(),\n",
+ " 'Storage': fs_full.statistics.sizes['ThermalStorage'].max().item(),\n",
+ " },\n",
+ " 'Clustered (3 days)': {\n",
+ " 'Time [s]': time_clustering + time_clustered,\n",
+ " 'Cost [β¬]': fs_clustered.solution['objective'].item(),\n",
+ " 'Boiler': fs_clustered.statistics.sizes['Boiler(Heat)'].max().item(),\n",
+ " 'Storage': fs_clustered.statistics.sizes['ThermalStorage'].max().item(),\n",
+ " },\n",
+ " 'Two-Stage': {\n",
+ " 'Time [s]': total_two_stage,\n",
+ " 'Cost [β¬]': fs_dispatch.solution['objective'].item(),\n",
+ " 'Boiler': sizes_with_margin['Boiler(Heat)'],\n",
+ " 'Storage': sizes_with_margin['ThermalStorage'],\n",
+ " },\n",
+ "}\n",
+ "\n",
+ "comparison = pd.DataFrame(results).T\n",
+ "baseline_cost = comparison.loc['Full (baseline)', 'Cost [β¬]']\n",
+ "baseline_time = comparison.loc['Full (baseline)', 'Time [s]']\n",
+ "comparison['Cost Gap [%]'] = ((comparison['Cost [β¬]'] - baseline_cost) / abs(baseline_cost) * 100).round(2)\n",
+ "comparison['Speedup'] = (baseline_time / comparison['Time [s]']).round(1)\n",
+ "\n",
+ "comparison.style.format(\n",
+ " {\n",
+ " 'Time [s]': '{:.2f}',\n",
+ " 'Cost [β¬]': '{:,.0f}',\n",
+ " 'Boiler': '{:.1f}',\n",
+ " 'Storage': '{:.0f}',\n",
+ " 'Cost Gap [%]': '{:.2f}',\n",
+ " 'Speedup': '{:.1f}x',\n",
+ " }\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "23",
+ "metadata": {},
+ "source": [
+ "## Visualize Optimization Results\n",
+ "\n",
+ "Use the built-in statistics plotting to compare results across periods and scenarios:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "24",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Plot flow rates with automatic faceting by period and scenario\n",
+ "fs_full.statistics.plot.flows(component='Boiler')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "25",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Side-by-side comparison using the Comparison class\n",
+ "comp = fx.Comparison([fs_full, fs_dispatch])\n",
+ "comp.statistics.plot.balance('Heat')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "26",
+ "metadata": {},
+ "source": [
+ "## Expand Clustered Solution to Full Resolution\n",
+ "\n",
+ "Use `expand_solution()` to map the clustered results back to all original timesteps:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "27",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Expand the clustered solution\n",
+ "fs_expanded = fs_clustered.transform.expand_solution()\n",
+ "\n",
+ "print(f'Expanded: {len(fs_clustered.timesteps)} β {len(fs_expanded.timesteps)} timesteps')\n",
+ "print(f'Cost (objective): {fs_expanded.solution[\"objective\"].item():,.0f} β¬')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "28",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Compare expanded solution - shows the repeated cluster patterns\n",
+ "fs_expanded.statistics.plot.flows(component='Boiler')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "29",
+ "metadata": {},
+ "source": [
+ "## Key Considerations for Multi-Period Clustering\n",
+ "\n",
+ "### 1. Independent Clustering per Period/Scenario\n",
+ "\n",
+ "Each period and scenario combination is clustered independently because:\n",
+ "- Demand patterns may differ across years (growth, seasonality)\n",
+ "- Scenarios represent different futures that shouldn't be mixed\n",
+ "- Investment decisions must be robust across all combinations\n",
+ "\n",
+ "### 2. Safety Margins\n",
+ "\n",
+ "Multi-period systems often warrant larger safety margins (10-15%) because:\n",
+ "- More uncertainty across multiple years\n",
+ "- Investments made once must work for all periods\n",
+ "- Scenario weights may not perfectly represent actual outcomes\n",
+ "\n",
+ "### 3. Computational Benefits\n",
+ "\n",
+ "Clustering becomes more valuable as problem size grows:\n",
+ "\n",
+ "| Scenario | Full Problem | With Clustering |\n",
+ "|----------|--------------|----------------|\n",
+ "| 1 period, 1 scenario, 365 days | 8,760 timesteps | ~730 (10 typical days) |\n",
+ "| 3 periods, 2 scenarios, 365 days | 52,560 timesteps | ~4,380 |\n",
+ "| 10 periods, 3 scenarios, 365 days | 262,800 timesteps | ~21,900 |\n",
+ "\n",
+ "The speedup factor increases with problem size."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "30",
+ "metadata": {},
+ "source": [
+ "## Summary\n",
+ "\n",
+ "You learned how to:\n",
+ "\n",
+ "- Load **multi-period systems** with periods and scenarios\n",
+ "- Use **`transform.isel()`** to select time subsets\n",
+ "- Apply **`cluster()`** to multi-dimensional FlowSystems\n",
+ "- **Visualize clustering** with the `.plot` accessor (compare, duration curves, heatmaps)\n",
+ "- Use the **two-stage workflow** for robust investment optimization\n",
+ "- **Expand solutions** back to full resolution with `expand_solution()`\n",
+ "\n",
+ "### Key Takeaways\n",
+ "\n",
+ "1. **Clustering is applied per period/scenario**: Each combination gets independent typical periods\n",
+ "2. **Investments are shared**: Component sizes are optimized once across all periods/scenarios\n",
+ "3. **Use larger safety margins**: Multi-period uncertainty warrants 10-15% buffers\n",
+ "4. **Two-stage is recommended**: Fast sizing with clustering, accurate dispatch at full resolution\n",
+ "5. **Built-in plotting**: Use `.plot` accessor for automatic faceting by period/scenario\n",
+ "\n",
+ "### API Reference\n",
+ "\n",
+ "```python\n",
+ "# Load multi-period system\n",
+ "fs = fx.FlowSystem.from_netcdf('multiperiod_system.nc4')\n",
+ "\n",
+ "# Select time subset (optional)\n",
+ "fs = fs.transform.isel(time=slice(0, 168)) # First 168 timesteps\n",
+ "\n",
+ "# Cluster (applies per period/scenario)\n",
+ "fs_clustered = fs.transform.cluster(\n",
+ " n_clusters=10,\n",
+ " cluster_duration='1D',\n",
+ " time_series_for_high_peaks=['Demand(Flow)|fixed_relative_profile'],\n",
+ ")\n",
+ "\n",
+ "# Visualize clustering quality\n",
+ "fs_clustered.clustering.plot.compare(variable='Demand(Flow)|profile')\n",
+ "fs_clustered.clustering.plot.heatmap()\n",
+ "\n",
+ "# Two-stage workflow\n",
+ "fs_clustered.optimize(solver)\n",
+ "sizes = {k: v.max().item() * 1.10 for k, v in fs_clustered.statistics.sizes.items()}\n",
+ "fs_dispatch = fs.transform.fix_sizes(sizes)\n",
+ "fs_dispatch.optimize(solver)\n",
+ "\n",
+ "# Visualize results\n",
+ "fs_dispatch.statistics.plot.flows(component='Boiler')\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "name": "python",
+ "version": "3.11"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/notebooks/08e-clustering-internals.ipynb b/docs/notebooks/08e-clustering-internals.ipynb
new file mode 100644
index 000000000..506a01ed9
--- /dev/null
+++ b/docs/notebooks/08e-clustering-internals.ipynb
@@ -0,0 +1,293 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "0",
+ "metadata": {},
+ "source": [
+ "# Clustering Internals\n",
+ "\n",
+ "Understanding the data structures and visualization tools behind time series clustering.\n",
+ "\n",
+ "This notebook demonstrates:\n",
+ "\n",
+ "- **Data structures**: `Clustering`, `ClusterResult`, and `ClusterStructure`\n",
+ "- **Plot accessor**: Built-in visualizations via `.plot`\n",
+ "- **Data expansion**: Using `expand_data()` to map aggregated data back to original timesteps\n",
+ "\n",
+ "!!! note \"Prerequisites\"\n",
+ " This notebook assumes familiarity with [08c-clustering](08c-clustering.ipynb)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from data.generate_example_systems import create_district_heating_system\n",
+ "\n",
+ "import flixopt as fx\n",
+ "\n",
+ "fx.CONFIG.notebook()\n",
+ "\n",
+ "flow_system = create_district_heating_system()\n",
+ "flow_system.connect_and_transform()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2",
+ "metadata": {},
+ "source": [
+ "## Clustering Metadata\n",
+ "\n",
+ "After calling `cluster()`, metadata is stored in `fs.clustering`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fs_clustered = flow_system.transform.cluster(\n",
+ " n_clusters=8,\n",
+ " cluster_duration='1D',\n",
+ " time_series_for_high_peaks=['HeatDemand(Q_th)|fixed_relative_profile'],\n",
+ ")\n",
+ "\n",
+ "fs_clustered.clustering"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4",
+ "metadata": {},
+ "source": [
+ "The `Clustering` contains:\n",
+ "- **`result`**: A `ClusterResult` with timestep mapping and weights\n",
+ "- **`result.cluster_structure`**: A `ClusterStructure` with cluster assignments"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fs_clustered.clustering.result"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "fs_clustered.clustering.result.cluster_structure"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7",
+ "metadata": {},
+ "source": [
+ "## Visualizing Clustering\n",
+ "\n",
+ "The `.plot` accessor provides built-in visualizations for understanding clustering results."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Compare original vs aggregated data as timeseries\n",
+ "# By default, plots all time-varying variables\n",
+ "fs_clustered.clustering.plot.compare()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Compare specific variables only\n",
+ "fs_clustered.clustering.plot.compare(variables='HeatDemand(Q_th)|fixed_relative_profile')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "10",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Duration curves show how well the aggregated data preserves the distribution\n",
+ "fs_clustered.clustering.plot.compare(kind='duration_curve').data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "11",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# View typical period profiles for each cluster\n",
+ "# Each line represents a cluster's representative day\n",
+ "fs_clustered.clustering.plot.clusters(variables='HeatDemand(Q_th)|fixed_relative_profile')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "12",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Heatmap shows cluster assignments for each original period\n",
+ "fs_clustered.clustering.plot.heatmap()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "13",
+ "metadata": {},
+ "source": [
+ "## Expanding Aggregated Data\n",
+ "\n",
+ "The `ClusterResult.expand_data()` method maps aggregated data back to original timesteps.\n",
+ "This is useful for comparing clustering results before optimization:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "14",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Get original and aggregated data\n",
+ "result = fs_clustered.clustering.result\n",
+ "original = result.original_data['HeatDemand(Q_th)|fixed_relative_profile']\n",
+ "aggregated = result.aggregated_data['HeatDemand(Q_th)|fixed_relative_profile']\n",
+ "\n",
+ "# Expand aggregated data back to original timesteps\n",
+ "expanded = result.expand_data(aggregated)\n",
+ "\n",
+ "print(f'Original: {len(original.time)} timesteps')\n",
+ "print(f'Aggregated: {len(aggregated.time)} timesteps')\n",
+ "print(f'Expanded: {len(expanded.time)} timesteps')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "15",
+ "metadata": {},
+ "source": [
+ "## Summary\n",
+ "\n",
+ "| Class | Purpose |\n",
+ "|-------|--------|\n",
+ "| `Clustering` | Stored on `fs.clustering` after `cluster()` |\n",
+ "| `ClusterResult` | Contains timestep mapping, weights, and `expand_data()` method |\n",
+ "| `ClusterStructure` | Maps original periods to clusters |\n",
+ "\n",
+ "### Plot Accessor Methods\n",
+ "\n",
+ "| Method | Description |\n",
+ "|--------|-------------|\n",
+ "| `plot.compare()` | Compare original vs aggregated data (timeseries) |\n",
+ "| `plot.compare(kind='duration_curve')` | Compare as duration curves |\n",
+ "| `plot.clusters()` | View each cluster's profile |\n",
+ "| `plot.heatmap()` | Visualize cluster assignments |\n",
+ "\n",
+ "### Key Parameters\n",
+ "\n",
+ "```python\n",
+ "# Compare with options\n",
+ "clustering.plot.compare(\n",
+ " variables='Demand|profile', # Single variable, list, or None (all)\n",
+ " kind='timeseries', # 'timeseries' or 'duration_curve'\n",
+ " select={'scenario': 'Base'}, # xarray-style selection\n",
+ " colors='viridis', # Colorscale name, list, or dict\n",
+ " facet_col='period', # Facet by period if present\n",
+ " facet_row='scenario', # Facet by scenario if present\n",
+ ")\n",
+ "\n",
+ "# Heatmap shows cluster assignments (no variable needed)\n",
+ "clustering.plot.heatmap()\n",
+ "\n",
+ "# Expand aggregated data to original timesteps\n",
+ "result = clustering.result\n",
+ "expanded = result.expand_data(aggregated_data)\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "16",
+ "metadata": {},
+ "source": [
+ "## Cluster Weights\n",
+ "\n",
+ "Each representative timestep has a weight equal to the number of original periods it represents.\n",
+ "This ensures operational costs scale correctly:\n",
+ "\n",
+ "$$\\text{Objective} = \\sum_{t \\in \\text{typical}} w_t \\cdot c_t$$\n",
+ "\n",
+ "The weights sum to the original timestep count:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "17",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "print(f'Sum of weights: {fs_clustered.cluster_weight.sum().item():.0f}')\n",
+ "print(f'Original timesteps: {len(flow_system.timesteps)}')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "18",
+ "metadata": {},
+ "source": [
+ "## Solution Expansion\n",
+ "\n",
+ "After optimization, `expand_solution()` maps results back to full resolution:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "19",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "solver = fx.solvers.HighsSolver(mip_gap=0.01, log_to_console=False)\n",
+ "fs_clustered.optimize(solver)\n",
+ "\n",
+ "fs_expanded = fs_clustered.transform.expand_solution()\n",
+ "\n",
+ "print(f'Clustered: {len(fs_clustered.timesteps)} timesteps')\n",
+ "print(f'Expanded: {len(fs_expanded.timesteps)} timesteps')"
+ ]
+ }
+ ],
+ "metadata": {},
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/docs/notebooks/09-plotting-and-data-access.ipynb b/docs/notebooks/09-plotting-and-data-access.ipynb
index a4803adf4..39fa788da 100644
--- a/docs/notebooks/09-plotting-and-data-access.ipynb
+++ b/docs/notebooks/09-plotting-and-data-access.ipynb
@@ -11,7 +11,6 @@
"\n",
"This notebook covers:\n",
"\n",
- "- Loading saved FlowSystems from NetCDF files\n",
"- Accessing data (flow rates, sizes, effects, charge states)\n",
"- Time series plots (balance, flows, storage)\n",
"- Aggregated plots (sizes, effects, duration curves)\n",
@@ -36,7 +35,7 @@
"metadata": {},
"outputs": [],
"source": [
- "from pathlib import Path\n",
+ "from data.generate_example_systems import create_complex_system, create_multiperiod_system, create_simple_system\n",
"\n",
"import flixopt as fx\n",
"\n",
@@ -48,9 +47,9 @@
"id": "3",
"metadata": {},
"source": [
- "## Generate Example Data\n",
+ "## Generate Example Systems\n",
"\n",
- "First, run the script that generates three example FlowSystems with solutions:"
+ "First, create three example FlowSystems with solutions:"
]
},
{
@@ -60,35 +59,19 @@
"metadata": {},
"outputs": [],
"source": [
- "# Run the generation script (only needed once, or to regenerate)\n",
- "!python data/generate_example_systems.py > /dev/null 2>&1"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "5",
- "metadata": {},
- "source": [
- "## 1. Loading Saved FlowSystems\n",
+ "# Create and optimize the example systems\n",
+ "solver = fx.solvers.HighsSolver(mip_gap=0.01, log_to_console=False)\n",
"\n",
- "FlowSystems can be saved to and loaded from NetCDF files, preserving the full structure and solution:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "6",
- "metadata": {},
- "outputs": [],
- "source": [
- "DATA_DIR = Path('data')\n",
+ "simple = create_simple_system()\n",
+ "simple.optimize(solver)\n",
+ "\n",
+ "complex_sys = create_complex_system()\n",
+ "complex_sys.optimize(solver)\n",
"\n",
- "# Load the three example systems\n",
- "simple = fx.FlowSystem.from_netcdf(DATA_DIR / 'simple_system.nc4')\n",
- "complex_sys = fx.FlowSystem.from_netcdf(DATA_DIR / 'complex_system.nc4')\n",
- "multiperiod = fx.FlowSystem.from_netcdf(DATA_DIR / 'multiperiod_system.nc4')\n",
+ "multiperiod = create_multiperiod_system()\n",
+ "multiperiod.optimize(solver)\n",
"\n",
- "print('Loaded systems:')\n",
+ "print('Created systems:')\n",
"print(f' simple: {len(simple.components)} components, {len(simple.buses)} buses')\n",
"print(f' complex_sys: {len(complex_sys.components)} components, {len(complex_sys.buses)} buses')\n",
"print(f' multiperiod: {len(multiperiod.components)} components, dims={dict(multiperiod.solution.sizes)}')"
@@ -96,7 +79,7 @@
},
{
"cell_type": "markdown",
- "id": "7",
+ "id": "5",
"metadata": {},
"source": [
"## 2. Quick Overview: Balance Plot\n",
@@ -107,7 +90,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "8",
+ "id": "6",
"metadata": {},
"outputs": [],
"source": [
@@ -117,7 +100,7 @@
},
{
"cell_type": "markdown",
- "id": "9",
+ "id": "7",
"metadata": {},
"source": [
"### Accessing Plot Data\n",
@@ -128,7 +111,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "10",
+ "id": "8",
"metadata": {},
"outputs": [],
"source": [
@@ -142,7 +125,7 @@
},
{
"cell_type": "markdown",
- "id": "11",
+ "id": "9",
"metadata": {},
"source": [
"### Energy Totals\n",
@@ -153,7 +136,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "12",
+ "id": "10",
"metadata": {},
"outputs": [],
"source": [
@@ -167,7 +150,7 @@
},
{
"cell_type": "markdown",
- "id": "13",
+ "id": "11",
"metadata": {},
"source": [
"## 3. Time Series Plots"
@@ -175,7 +158,7 @@
},
{
"cell_type": "markdown",
- "id": "14",
+ "id": "12",
"metadata": {},
"source": [
"### 3.1 Balance Plot\n",
@@ -186,7 +169,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "15",
+ "id": "13",
"metadata": {},
"outputs": [],
"source": [
@@ -196,7 +179,7 @@
},
{
"cell_type": "markdown",
- "id": "16",
+ "id": "14",
"metadata": {},
"source": [
"### 3.2 Carrier Balance\n",
@@ -207,7 +190,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "17",
+ "id": "15",
"metadata": {},
"outputs": [],
"source": [
@@ -217,7 +200,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "18",
+ "id": "16",
"metadata": {},
"outputs": [],
"source": [
@@ -226,7 +209,7 @@
},
{
"cell_type": "markdown",
- "id": "19",
+ "id": "17",
"metadata": {},
"source": [
"### 3.3 Flow Rates\n",
@@ -237,7 +220,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "20",
+ "id": "18",
"metadata": {},
"outputs": [],
"source": [
@@ -248,7 +231,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "21",
+ "id": "19",
"metadata": {},
"outputs": [],
"source": [
@@ -258,7 +241,7 @@
},
{
"cell_type": "markdown",
- "id": "22",
+ "id": "20",
"metadata": {},
"source": [
"### 3.4 Storage Plot\n",
@@ -269,7 +252,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "23",
+ "id": "21",
"metadata": {},
"outputs": [],
"source": [
@@ -278,7 +261,7 @@
},
{
"cell_type": "markdown",
- "id": "24",
+ "id": "22",
"metadata": {},
"source": [
"### 3.5 Charge States Plot\n",
@@ -289,7 +272,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "25",
+ "id": "23",
"metadata": {},
"outputs": [],
"source": [
@@ -298,7 +281,7 @@
},
{
"cell_type": "markdown",
- "id": "26",
+ "id": "24",
"metadata": {},
"source": [
"## 4. Aggregated Plots"
@@ -306,7 +289,7 @@
},
{
"cell_type": "markdown",
- "id": "27",
+ "id": "25",
"metadata": {},
"source": [
"### 4.1 Sizes Plot\n",
@@ -317,7 +300,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "28",
+ "id": "26",
"metadata": {},
"outputs": [],
"source": [
@@ -326,7 +309,7 @@
},
{
"cell_type": "markdown",
- "id": "29",
+ "id": "27",
"metadata": {},
"source": [
"### 4.2 Effects Plot\n",
@@ -337,7 +320,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "30",
+ "id": "28",
"metadata": {},
"outputs": [],
"source": [
@@ -347,7 +330,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "31",
+ "id": "29",
"metadata": {},
"outputs": [],
"source": [
@@ -358,7 +341,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "32",
+ "id": "30",
"metadata": {},
"outputs": [],
"source": [
@@ -367,7 +350,7 @@
},
{
"cell_type": "markdown",
- "id": "33",
+ "id": "31",
"metadata": {},
"source": [
"### 4.3 Duration Curve\n",
@@ -378,7 +361,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "34",
+ "id": "32",
"metadata": {},
"outputs": [],
"source": [
@@ -388,7 +371,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "35",
+ "id": "33",
"metadata": {},
"outputs": [],
"source": [
@@ -398,7 +381,7 @@
},
{
"cell_type": "markdown",
- "id": "36",
+ "id": "34",
"metadata": {},
"source": [
"## 5. Heatmaps\n",
@@ -409,7 +392,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "37",
+ "id": "35",
"metadata": {},
"outputs": [],
"source": [
@@ -420,7 +403,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "38",
+ "id": "36",
"metadata": {},
"outputs": [],
"source": [
@@ -431,7 +414,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "39",
+ "id": "37",
"metadata": {},
"outputs": [],
"source": [
@@ -441,7 +424,7 @@
},
{
"cell_type": "markdown",
- "id": "40",
+ "id": "38",
"metadata": {},
"source": [
"## 6. Sankey Diagrams\n",
@@ -451,7 +434,7 @@
},
{
"cell_type": "markdown",
- "id": "41",
+ "id": "39",
"metadata": {},
"source": [
"### 6.1 Flow Sankey\n",
@@ -462,7 +445,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "42",
+ "id": "40",
"metadata": {},
"outputs": [],
"source": [
@@ -472,7 +455,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "43",
+ "id": "41",
"metadata": {},
"outputs": [],
"source": [
@@ -482,7 +465,7 @@
},
{
"cell_type": "markdown",
- "id": "44",
+ "id": "42",
"metadata": {},
"source": [
"### 6.2 Sizes Sankey\n",
@@ -493,7 +476,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "45",
+ "id": "43",
"metadata": {},
"outputs": [],
"source": [
@@ -502,7 +485,7 @@
},
{
"cell_type": "markdown",
- "id": "46",
+ "id": "44",
"metadata": {},
"source": [
"### 6.3 Peak Flow Sankey\n",
@@ -513,7 +496,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "47",
+ "id": "45",
"metadata": {},
"outputs": [],
"source": [
@@ -522,7 +505,7 @@
},
{
"cell_type": "markdown",
- "id": "48",
+ "id": "46",
"metadata": {},
"source": [
"### 6.4 Effects Sankey\n",
@@ -533,7 +516,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "49",
+ "id": "47",
"metadata": {},
"outputs": [],
"source": [
@@ -543,7 +526,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "50",
+ "id": "48",
"metadata": {},
"outputs": [],
"source": [
@@ -553,7 +536,7 @@
},
{
"cell_type": "markdown",
- "id": "51",
+ "id": "49",
"metadata": {},
"source": [
"### 6.5 Filtering with `select`\n",
@@ -564,7 +547,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "52",
+ "id": "50",
"metadata": {},
"outputs": [],
"source": [
@@ -574,7 +557,7 @@
},
{
"cell_type": "markdown",
- "id": "53",
+ "id": "51",
"metadata": {},
"source": [
"## 7. Topology Visualization\n",
@@ -584,7 +567,7 @@
},
{
"cell_type": "markdown",
- "id": "54",
+ "id": "52",
"metadata": {},
"source": [
"### 7.1 Topology Plot\n",
@@ -595,7 +578,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "55",
+ "id": "53",
"metadata": {},
"outputs": [],
"source": [
@@ -605,7 +588,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "56",
+ "id": "54",
"metadata": {},
"outputs": [],
"source": [
@@ -614,7 +597,7 @@
},
{
"cell_type": "markdown",
- "id": "57",
+ "id": "55",
"metadata": {},
"source": [
"### 7.2 Topology Info\n",
@@ -625,7 +608,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "58",
+ "id": "56",
"metadata": {},
"outputs": [],
"source": [
@@ -642,7 +625,7 @@
},
{
"cell_type": "markdown",
- "id": "59",
+ "id": "57",
"metadata": {},
"source": [
"## 8. Multi-Period/Scenario Data\n",
@@ -653,7 +636,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "60",
+ "id": "58",
"metadata": {},
"outputs": [],
"source": [
@@ -666,7 +649,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "61",
+ "id": "59",
"metadata": {},
"outputs": [],
"source": [
@@ -677,7 +660,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "62",
+ "id": "60",
"metadata": {},
"outputs": [],
"source": [
@@ -688,7 +671,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "63",
+ "id": "61",
"metadata": {},
"outputs": [],
"source": [
@@ -698,7 +681,7 @@
},
{
"cell_type": "markdown",
- "id": "64",
+ "id": "62",
"metadata": {},
"source": [
"## 9. Color Customization\n",
@@ -709,7 +692,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "65",
+ "id": "63",
"metadata": {},
"outputs": [],
"source": [
@@ -720,7 +703,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "66",
+ "id": "64",
"metadata": {},
"outputs": [],
"source": [
@@ -731,7 +714,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "67",
+ "id": "65",
"metadata": {},
"outputs": [],
"source": [
@@ -749,7 +732,7 @@
},
{
"cell_type": "markdown",
- "id": "68",
+ "id": "66",
"metadata": {},
"source": [
"## 10. Exporting Results\n",
@@ -760,7 +743,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "69",
+ "id": "67",
"metadata": {},
"outputs": [],
"source": [
@@ -775,7 +758,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "70",
+ "id": "68",
"metadata": {},
"outputs": [],
"source": [
@@ -787,7 +770,7 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "71",
+ "id": "69",
"metadata": {},
"outputs": [],
"source": [
@@ -800,7 +783,7 @@
},
{
"cell_type": "markdown",
- "id": "72",
+ "id": "70",
"metadata": {},
"source": [
"## Summary\n",
diff --git a/docs/notebooks/data/__init__.py b/docs/notebooks/data/__init__.py
new file mode 100644
index 000000000..fd6d62d1d
--- /dev/null
+++ b/docs/notebooks/data/__init__.py
@@ -0,0 +1 @@
+# Data generation utilities for flixopt documentation examples
diff --git a/docs/notebooks/data/generate_example_systems.py b/docs/notebooks/data/generate_example_systems.py
index 556463302..c53322ef2 100644
--- a/docs/notebooks/data/generate_example_systems.py
+++ b/docs/notebooks/data/generate_example_systems.py
@@ -1,26 +1,62 @@
-"""Generate example FlowSystem files for the plotting notebook.
+"""Generate example FlowSystem files for notebooks.
-This script creates three FlowSystems of varying complexity:
+This script creates FlowSystems of varying complexity:
1. simple_system - Basic heat system (boiler + storage + sink)
2. complex_system - Multi-carrier with multiple effects and piecewise efficiency
3. multiperiod_system - System with periods and scenarios
+4. district_heating_system - Real-world district heating data with investments (1 month)
+5. operational_system - Real-world district heating for operational planning (2 weeks, no investments)
+6. seasonal_storage_system - Solar thermal + seasonal pit storage (full year, 8760h)
Run this script to regenerate the example data files.
"""
+import sys
from pathlib import Path
import numpy as np
import pandas as pd
+# Handle imports in different contexts (direct run, package import, mkdocs-jupyter)
+try:
+ from .generate_realistic_profiles import (
+ ElectricityLoadGenerator,
+ GasPriceGenerator,
+ ThermalLoadGenerator,
+ load_electricity_prices,
+ load_weather,
+ )
+except ImportError:
+ # Add data directory to path for mkdocs-jupyter context
+ try:
+ _data_dir = Path(__file__).parent
+ except NameError:
+ _data_dir = Path('docs/notebooks/data')
+ if str(_data_dir) not in sys.path:
+ sys.path.insert(0, str(_data_dir))
+ from generate_realistic_profiles import (
+ ElectricityLoadGenerator,
+ GasPriceGenerator,
+ ThermalLoadGenerator,
+ load_electricity_prices,
+ load_weather,
+ )
+
import flixopt as fx
# Output directory (same as this script)
try:
OUTPUT_DIR = Path(__file__).parent
+ DATA_DIR = Path(__file__).parent # Zeitreihen2020.csv is in the same directory
except NameError:
# Running in notebook context (e.g., mkdocs-jupyter)
OUTPUT_DIR = Path('docs/notebooks/data')
+ DATA_DIR = Path('docs/notebooks/data')
+
+# Load shared data
+_weather = load_weather()
+_elec_prices = load_electricity_prices()
+_elec_prices.index = _elec_prices.index.tz_localize(None) # Remove timezone for compatibility
def create_simple_system() -> fx.FlowSystem:
@@ -29,27 +65,22 @@ def create_simple_system() -> fx.FlowSystem:
Components:
- Gas boiler (150 kW)
- Thermal storage (500 kWh)
- - Office heat demand
+ - Office heat demand (BDEW profile)
- One week, hourly resolution.
+ One week (January 2020), hourly resolution.
+ Uses realistic BDEW heat demand and seasonal gas prices.
"""
- # One week, hourly
- timesteps = pd.date_range('2024-01-15', periods=168, freq='h')
+ # One week, hourly (January 2020 for realistic data)
+ timesteps = pd.date_range('2020-01-15', periods=168, freq='h')
+ temp = _weather.loc[timesteps, 'temperature_C'].values
- # Create demand pattern
- hours = np.arange(168)
- hour_of_day = hours % 24
- day_of_week = (hours // 24) % 7
+ # BDEW office heat demand profile (scaled to fit 150 kW boiler)
+ thermal_gen = ThermalLoadGenerator()
+ heat_demand = thermal_gen.generate(timesteps, temp, 'office', annual_demand_kwh=15_000)
- base_demand = np.where((hour_of_day >= 7) & (hour_of_day <= 18), 80, 30)
- weekend_factor = np.where(day_of_week >= 5, 0.5, 1.0)
-
- np.random.seed(42)
- heat_demand = base_demand * weekend_factor + np.random.normal(0, 5, len(hours))
- heat_demand = np.clip(heat_demand, 20, 100)
-
- # Time-varying gas price
- gas_price = np.where((hour_of_day >= 6) & (hour_of_day <= 22), 0.08, 0.05)
+ # Seasonal gas price
+ gas_gen = GasPriceGenerator()
+ gas_price = gas_gen.generate(timesteps) / 1000 # EUR/kWh
fs = fx.FlowSystem(timesteps)
fs.add_carriers(
@@ -93,30 +124,32 @@ def create_complex_system() -> fx.FlowSystem:
- Heat pump
- Gas boiler (backup)
- Thermal storage
- - Heat demand
+ - Heat demand (BDEW retail profile)
+ - Electricity demand (BDEW commercial profile)
Effects: costs (objective), CO2
- Three days, hourly resolution.
+ Three days (June 2020), hourly resolution.
+ Uses realistic BDEW profiles and OPSD electricity prices.
"""
- timesteps = pd.date_range('2024-06-01', periods=72, freq='h')
- hours = np.arange(72)
- hour_of_day = hours % 24
+ timesteps = pd.date_range('2020-06-01', periods=72, freq='h')
+ temp = _weather.loc[timesteps, 'temperature_C'].values
- # Demand profiles
- np.random.seed(123)
- heat_demand = 50 + 30 * np.sin(2 * np.pi * hour_of_day / 24 - np.pi / 2) + np.random.normal(0, 5, 72)
- heat_demand = np.clip(heat_demand, 20, 100)
+ # BDEW demand profiles (scaled to fit component sizes)
+ thermal_gen = ThermalLoadGenerator()
+ heat_demand = thermal_gen.generate(timesteps, temp, 'retail', annual_demand_kwh=2_000)
- electricity_demand = 20 + 15 * np.sin(2 * np.pi * hour_of_day / 24) + np.random.normal(0, 3, 72)
- electricity_demand = np.clip(electricity_demand, 10, 50)
+ elec_gen = ElectricityLoadGenerator()
+ electricity_demand = elec_gen.generate(timesteps, 'commercial', annual_demand_kwh=50_000)
- # Price profiles
- electricity_price = np.where((hour_of_day >= 8) & (hour_of_day <= 20), 0.25, 0.12)
- gas_price = 0.06
+ # Real electricity prices (OPSD) and seasonal gas prices
+ electricity_price = _elec_prices.reindex(timesteps, method='ffill').values / 1000 # EUR/kWh
+ gas_gen = GasPriceGenerator()
+ gas_price = gas_gen.generate(timesteps) / 1000 # EUR/kWh
- # CO2 factors (kg/kWh)
- electricity_co2 = np.where((hour_of_day >= 8) & (hour_of_day <= 20), 0.4, 0.3) # Higher during peak
+ # CO2 factors (kg/kWh) - higher during peak hours
+ hour_of_day = timesteps.hour.values
+ electricity_co2 = np.where((hour_of_day >= 8) & (hour_of_day <= 20), 0.4, 0.3)
gas_co2 = 0.2
fs = fx.FlowSystem(timesteps)
@@ -229,6 +262,366 @@ def create_complex_system() -> fx.FlowSystem:
return fs
+def create_district_heating_system() -> fx.FlowSystem:
+ """Create a district heating system with BDEW profiles.
+
+ Uses realistic German data:
+ - One month (January 2020), hourly resolution
+ - BDEW industrial heat profile
+ - BDEW commercial electricity profile
+ - OPSD electricity prices
+ - Seasonal gas prices
+ - CHP, boiler, storage, and grid connections
+ - Investment optimization for sizing
+
+ Used by: 08a-aggregation, 08c-clustering, 08e-clustering-internals notebooks
+ """
+ # One month, hourly
+ timesteps = pd.date_range('2020-01-01', '2020-01-31 23:00:00', freq='h')
+ temp = _weather.loc[timesteps, 'temperature_C'].values
+
+ # BDEW profiles (MW scale for district heating)
+ thermal_gen = ThermalLoadGenerator()
+ heat_demand = thermal_gen.generate(timesteps, temp, 'industrial', annual_demand_kwh=15_000_000) / 1000 # MW
+
+ elec_gen = ElectricityLoadGenerator()
+ electricity_demand = elec_gen.generate(timesteps, 'commercial', annual_demand_kwh=5_000_000) / 1000 # MW
+
+ # Prices
+ electricity_price = _elec_prices.reindex(timesteps, method='ffill').values # EUR/MWh
+ gas_gen = GasPriceGenerator()
+ gas_price = gas_gen.generate(timesteps) # EUR/MWh
+
+ fs = fx.FlowSystem(timesteps)
+ fs.add_elements(
+ # Buses
+ fx.Bus('Electricity'),
+ fx.Bus('Heat'),
+ fx.Bus('Gas'),
+ fx.Bus('Coal'),
+ # Effects
+ fx.Effect('costs', 'β¬', 'Total Costs', is_standard=True, is_objective=True),
+ fx.Effect('CO2', 'kg', 'CO2 Emissions'),
+ # CHP unit with investment
+ fx.linear_converters.CHP(
+ 'CHP',
+ thermal_efficiency=0.58,
+ electrical_efficiency=0.22,
+ electrical_flow=fx.Flow('P_el', bus='Electricity', size=200),
+ thermal_flow=fx.Flow(
+ 'Q_th',
+ bus='Heat',
+ size=fx.InvestParameters(
+ minimum_size=100,
+ maximum_size=300,
+ effects_of_investment_per_size={'costs': 10},
+ ),
+ relative_minimum=0.3,
+ status_parameters=fx.StatusParameters(),
+ ),
+ fuel_flow=fx.Flow('Q_fu', bus='Coal'),
+ ),
+ # Gas Boiler with investment
+ fx.linear_converters.Boiler(
+ 'Boiler',
+ thermal_efficiency=0.85,
+ thermal_flow=fx.Flow(
+ 'Q_th',
+ bus='Heat',
+ size=fx.InvestParameters(
+ minimum_size=0,
+ maximum_size=150,
+ effects_of_investment_per_size={'costs': 5},
+ ),
+ relative_minimum=0.1,
+ status_parameters=fx.StatusParameters(),
+ ),
+ fuel_flow=fx.Flow('Q_fu', bus='Gas'),
+ ),
+ # Thermal Storage with investment
+ fx.Storage(
+ 'Storage',
+ capacity_in_flow_hours=fx.InvestParameters(
+ minimum_size=0,
+ maximum_size=1000,
+ effects_of_investment_per_size={'costs': 0.5},
+ ),
+ initial_charge_state=0,
+ eta_charge=1,
+ eta_discharge=1,
+ relative_loss_per_hour=0.001,
+ charging=fx.Flow('Charge', size=137, bus='Heat'),
+ discharging=fx.Flow('Discharge', size=158, bus='Heat'),
+ ),
+ # Fuel sources
+ fx.Source(
+ 'GasGrid',
+ outputs=[fx.Flow('Q_Gas', bus='Gas', size=1000, effects_per_flow_hour={'costs': gas_price, 'CO2': 0.3})],
+ ),
+ fx.Source(
+ 'CoalSupply',
+ outputs=[fx.Flow('Q_Coal', bus='Coal', size=1000, effects_per_flow_hour={'costs': 4.6, 'CO2': 0.3})],
+ ),
+ # Electricity grid
+ fx.Source(
+ 'GridBuy',
+ outputs=[
+ fx.Flow(
+ 'P_el',
+ bus='Electricity',
+ size=1000,
+ effects_per_flow_hour={'costs': electricity_price + 0.5, 'CO2': 0.3},
+ )
+ ],
+ ),
+ fx.Sink(
+ 'GridSell',
+ inputs=[fx.Flow('P_el', bus='Electricity', size=1000, effects_per_flow_hour=-(electricity_price - 0.5))],
+ ),
+ # Demands
+ fx.Sink('HeatDemand', inputs=[fx.Flow('Q_th', bus='Heat', size=1, fixed_relative_profile=heat_demand)]),
+ fx.Sink(
+ 'ElecDemand', inputs=[fx.Flow('P_el', bus='Electricity', size=1, fixed_relative_profile=electricity_demand)]
+ ),
+ )
+ return fs
+
+
+def create_operational_system() -> fx.FlowSystem:
+ """Create an operational district heating system (no investments).
+
+ Uses realistic German data (two weeks, January 2020):
+ - BDEW industrial heat profile
+ - BDEW commercial electricity profile
+ - OPSD electricity prices
+ - Seasonal gas prices
+ - CHP with startup costs
+ - Boiler with startup costs
+ - Storage with fixed capacity
+ - No investment parameters (for rolling horizon optimization)
+
+ Used by: 08b-rolling-horizon notebook
+ """
+ # Two weeks, hourly
+ timesteps = pd.date_range('2020-01-01', '2020-01-14 23:00:00', freq='h')
+ temp = _weather.loc[timesteps, 'temperature_C'].values
+
+ # BDEW profiles (MW scale)
+ thermal_gen = ThermalLoadGenerator()
+ heat_demand = thermal_gen.generate(timesteps, temp, 'industrial', annual_demand_kwh=15_000_000) / 1000 # MW
+
+ elec_gen = ElectricityLoadGenerator()
+ electricity_demand = elec_gen.generate(timesteps, 'commercial', annual_demand_kwh=5_000_000) / 1000 # MW
+
+ # Prices
+ electricity_price = _elec_prices.reindex(timesteps, method='ffill').values # EUR/MWh
+ gas_gen = GasPriceGenerator()
+ gas_price = gas_gen.generate(timesteps) # EUR/MWh
+
+ fs = fx.FlowSystem(timesteps)
+ fs.add_elements(
+ fx.Bus('Electricity'),
+ fx.Bus('Heat'),
+ fx.Bus('Gas'),
+ fx.Bus('Coal'),
+ fx.Effect('costs', 'β¬', 'Total Costs', is_standard=True, is_objective=True),
+ fx.Effect('CO2', 'kg', 'CO2 Emissions'),
+ # CHP with startup costs
+ fx.linear_converters.CHP(
+ 'CHP',
+ thermal_efficiency=0.58,
+ electrical_efficiency=0.22,
+ status_parameters=fx.StatusParameters(effects_per_startup=24000),
+ electrical_flow=fx.Flow('P_el', bus='Electricity', size=200),
+ thermal_flow=fx.Flow('Q_th', bus='Heat', size=200),
+ fuel_flow=fx.Flow('Q_fu', bus='Coal', size=288, relative_minimum=87 / 288, previous_flow_rate=100),
+ ),
+ # Boiler with startup costs
+ fx.linear_converters.Boiler(
+ 'Boiler',
+ thermal_efficiency=0.85,
+ thermal_flow=fx.Flow('Q_th', bus='Heat'),
+ fuel_flow=fx.Flow(
+ 'Q_fu',
+ bus='Gas',
+ size=95,
+ relative_minimum=12 / 95,
+ previous_flow_rate=20,
+ status_parameters=fx.StatusParameters(effects_per_startup=1000),
+ ),
+ ),
+ # Storage with fixed capacity
+ fx.Storage(
+ 'Storage',
+ capacity_in_flow_hours=684,
+ initial_charge_state=137,
+ minimal_final_charge_state=137,
+ maximal_final_charge_state=158,
+ eta_charge=1,
+ eta_discharge=1,
+ relative_loss_per_hour=0.001,
+ prevent_simultaneous_charge_and_discharge=True,
+ charging=fx.Flow('Charge', size=137, bus='Heat'),
+ discharging=fx.Flow('Discharge', size=158, bus='Heat'),
+ ),
+ fx.Source(
+ 'GasGrid',
+ outputs=[fx.Flow('Q_Gas', bus='Gas', size=1000, effects_per_flow_hour={'costs': gas_price, 'CO2': 0.3})],
+ ),
+ fx.Source(
+ 'CoalSupply',
+ outputs=[fx.Flow('Q_Coal', bus='Coal', size=1000, effects_per_flow_hour={'costs': 4.6, 'CO2': 0.3})],
+ ),
+ fx.Source(
+ 'GridBuy',
+ outputs=[
+ fx.Flow(
+ 'P_el',
+ bus='Electricity',
+ size=1000,
+ effects_per_flow_hour={'costs': electricity_price + 0.5, 'CO2': 0.3},
+ )
+ ],
+ ),
+ fx.Sink(
+ 'GridSell',
+ inputs=[fx.Flow('P_el', bus='Electricity', size=1000, effects_per_flow_hour=-(electricity_price - 0.5))],
+ ),
+ fx.Sink('HeatDemand', inputs=[fx.Flow('Q_th', bus='Heat', size=1, fixed_relative_profile=heat_demand)]),
+ fx.Sink(
+ 'ElecDemand', inputs=[fx.Flow('P_el', bus='Electricity', size=1, fixed_relative_profile=electricity_demand)]
+ ),
+ )
+ return fs
+
+
+def create_seasonal_storage_system() -> fx.FlowSystem:
+ """Create a district heating system with solar thermal and seasonal storage.
+
+ Demonstrates seasonal storage value with:
+ - Full year at hourly resolution (8760 timesteps)
+ - Solar thermal from PVGIS irradiance data
+ - Heat demand from BDEW industrial profile
+ - Large seasonal pit storage (bridges seasons)
+ - Gas boiler backup
+
+ This system clearly shows the value of inter-cluster storage linking:
+ - Summer: excess solar heat stored in pit
+ - Winter: stored heat reduces gas consumption
+
+ Uses realistic PVGIS solar irradiance and BDEW heat profiles.
+ Used by: 08c-clustering, 08c2-clustering-storage-modes notebooks
+ """
+ # Full year, hourly (use non-leap year to match TMY data which has 8760 hours)
+ timesteps = pd.date_range('2019-01-01', periods=8760, freq='h')
+ # Map to 2020 weather data (TMY has 8760 hours, no Feb 29)
+ temp = _weather['temperature_C'].values
+ ghi = _weather['ghi_W_m2'].values
+
+ # --- Solar thermal profile from PVGIS irradiance ---
+ # Normalize GHI to 0-1 range and apply collector efficiency
+ solar_profile = ghi / 1000 # Normalized (1000 W/mΒ² = 1.0)
+ solar_profile = np.clip(solar_profile, 0, 1)
+
+ # --- Heat demand from BDEW industrial profile ---
+ # Scale to MW (district heating scale)
+ # Use 2019 year for demandlib (non-leap year)
+ thermal_gen = ThermalLoadGenerator(year=2019)
+ heat_demand_kw = thermal_gen.generate(timesteps, temp, 'industrial', annual_demand_kwh=20_000_000)
+ heat_demand = heat_demand_kw / 1000 # Convert to MW
+
+ # --- Gas price with seasonal variation ---
+ gas_gen = GasPriceGenerator()
+ gas_price = gas_gen.generate(timesteps) # EUR/MWh
+
+ fs = fx.FlowSystem(timesteps)
+ fs.add_carriers(
+ fx.Carrier('gas', '#3498db', 'MW'),
+ fx.Carrier('heat', '#e74c3c', 'MW'),
+ )
+ fs.add_elements(
+ # Buses
+ fx.Bus('Gas', carrier='gas'),
+ fx.Bus('Heat', carrier='heat'),
+ # Effects
+ fx.Effect('costs', 'β¬', 'Total Costs', is_standard=True, is_objective=True),
+ fx.Effect('CO2', 'kg', 'CO2 Emissions'),
+ # Solar thermal collector (investment) - profile includes 70% collector efficiency
+ # Costs annualized for single-year analysis
+ fx.Source(
+ 'SolarThermal',
+ outputs=[
+ fx.Flow(
+ 'Q_th',
+ bus='Heat',
+ size=fx.InvestParameters(
+ minimum_size=0,
+ maximum_size=20, # MW peak
+ effects_of_investment_per_size={'costs': 15000}, # β¬/MW (annualized)
+ ),
+ fixed_relative_profile=solar_profile * 0.7, # 70% collector efficiency
+ )
+ ],
+ ),
+ # Gas boiler (backup)
+ fx.linear_converters.Boiler(
+ 'GasBoiler',
+ thermal_efficiency=0.90,
+ thermal_flow=fx.Flow(
+ 'Q_th',
+ bus='Heat',
+ size=fx.InvestParameters(
+ minimum_size=0,
+ maximum_size=8, # MW
+ effects_of_investment_per_size={'costs': 20000}, # β¬/MW (annualized)
+ ),
+ ),
+ fuel_flow=fx.Flow('Q_fu', bus='Gas'),
+ ),
+ # Gas supply (higher price makes solar+storage more attractive)
+ fx.Source(
+ 'GasGrid',
+ outputs=[
+ fx.Flow(
+ 'Q_gas',
+ bus='Gas',
+ size=20,
+ effects_per_flow_hour={'costs': gas_price * 1.5, 'CO2': 0.2}, # β¬/MWh
+ )
+ ],
+ ),
+ # Seasonal pit storage (large capacity for seasonal shifting)
+ fx.Storage(
+ 'SeasonalStorage',
+ capacity_in_flow_hours=fx.InvestParameters(
+ minimum_size=0,
+ maximum_size=50000, # MWh - large for seasonal storage
+ effects_of_investment_per_size={'costs': 20}, # β¬/MWh (pit storage is cheap)
+ ),
+ initial_charge_state='equals_final', # Yearly cyclic
+ eta_charge=0.95,
+ eta_discharge=0.95,
+ relative_loss_per_hour=0.0001, # Very low losses for pit storage
+ charging=fx.Flow(
+ 'Charge',
+ bus='Heat',
+ size=fx.InvestParameters(maximum_size=10, effects_of_investment_per_size={'costs': 5000}),
+ ),
+ discharging=fx.Flow(
+ 'Discharge',
+ bus='Heat',
+ size=fx.InvestParameters(maximum_size=10, effects_of_investment_per_size={'costs': 5000}),
+ ),
+ ),
+ # Heat demand
+ fx.Sink(
+ 'HeatDemand',
+ inputs=[fx.Flow('Q_th', bus='Heat', size=1, fixed_relative_profile=heat_demand)],
+ ),
+ )
+ return fs
+
+
def create_multiperiod_system() -> fx.FlowSystem:
"""Create a system with multiple periods and scenarios.
@@ -236,10 +629,14 @@ def create_multiperiod_system() -> fx.FlowSystem:
- 3 planning periods (years 2024, 2025, 2026)
- 2 scenarios (high demand, low demand)
- Each period: 48 hours (2 days representative)
+ Each period: 336 hours (2 weeks) - suitable for clustering demonstrations.
+ Use transform.sisel() to select subsets if needed.
+
+ Uses BDEW residential heat profile as base, scaled for scenarios.
"""
- timesteps = pd.date_range('2024-01-01', periods=48, freq='h')
- hour_of_day = np.arange(48) % 24
+ n_hours = 336 # 2 weeks
+ timesteps = pd.date_range('2020-01-01', periods=n_hours, freq='h')
+ temp = _weather.loc[timesteps, 'temperature_C'].values
# Period definitions (years)
periods = pd.Index([2024, 2025, 2026], name='period')
@@ -248,25 +645,27 @@ def create_multiperiod_system() -> fx.FlowSystem:
scenarios = pd.Index(['high_demand', 'low_demand'], name='scenario')
scenario_weights = np.array([0.3, 0.7])
- # Base demand pattern (hourly)
- base_pattern = np.where((hour_of_day >= 7) & (hour_of_day <= 18), 80.0, 35.0)
+ # BDEW residential heat profile as base (scaled to fit 250 kW boiler with scenarios)
+ thermal_gen = ThermalLoadGenerator()
+ base_demand = thermal_gen.generate(timesteps, temp, 'residential', annual_demand_kwh=30_000)
# Scenario-specific scaling
- np.random.seed(42)
- high_demand = base_pattern * 1.2 + np.random.normal(0, 5, 48)
- low_demand = base_pattern * 0.85 + np.random.normal(0, 3, 48)
+ high_demand = base_demand * 1.3
+ low_demand = base_demand * 0.7
# Create DataFrame with scenario columns
heat_demand = pd.DataFrame(
{
- 'high_demand': np.clip(high_demand, 20, 120),
- 'low_demand': np.clip(low_demand, 15, 90),
+ 'high_demand': high_demand,
+ 'low_demand': low_demand,
},
index=timesteps,
)
- # Gas price varies by period (rising costs)
- gas_prices = np.array([0.06, 0.08, 0.10]) # Per period
+ # Gas price varies by period (rising costs, based on seasonal price)
+ gas_gen = GasPriceGenerator()
+ base_gas = gas_gen.generate(timesteps).mean() / 1000 # Average EUR/kWh
+ gas_prices = np.array([base_gas, base_gas * 1.2, base_gas * 1.5]) # Rising costs per period
fs = fx.FlowSystem(
timesteps,
@@ -316,28 +715,23 @@ def create_multiperiod_system() -> fx.FlowSystem:
def main():
"""Generate all example systems and save to netCDF."""
- solver = fx.solvers.HighsSolver(log_to_console=False)
-
systems = [
('simple_system', create_simple_system),
('complex_system', create_complex_system),
('multiperiod_system', create_multiperiod_system),
+ ('district_heating_system', create_district_heating_system),
+ ('operational_system', create_operational_system),
+ ('seasonal_storage_system', create_seasonal_storage_system),
]
for name, create_func in systems:
print(f'Creating {name}...')
fs = create_func()
- print(' Optimizing...')
- fs.optimize(solver)
-
output_path = OUTPUT_DIR / f'{name}.nc4'
print(f' Saving to {output_path}...')
fs.to_netcdf(output_path, overwrite=True)
- print(f' Done. Objective: {fs.solution["objective"].item():.2f}')
- print()
-
print('All systems generated successfully!')
diff --git a/docs/notebooks/data/generate_realistic_profiles.py b/docs/notebooks/data/generate_realistic_profiles.py
new file mode 100644
index 000000000..5fde58397
--- /dev/null
+++ b/docs/notebooks/data/generate_realistic_profiles.py
@@ -0,0 +1,262 @@
+"""Generate realistic German energy profiles for flixOpt examples.
+
+This module provides functions to create realistic time series data for:
+- Thermal load profiles (BDEW standard load profiles via demandlib)
+- Electricity load profiles (BDEW standard load profiles via demandlib)
+- Solar generation profiles (via pvlib)
+- Energy prices (bundled OPSD data)
+- Weather data (bundled PVGIS TMY data for Dresden)
+
+Example:
+ >>> from generate_realistic_profiles import load_weather, ThermalLoadGenerator
+ >>> weather = load_weather()
+ >>> thermal = ThermalLoadGenerator()
+ >>> heat_demand = thermal.generate(weather.index, weather['temperature_C'], 'residential', 50000)
+"""
+
+from __future__ import annotations
+
+import warnings
+from pathlib import Path
+
+import holidays
+import numpy as np
+import pandas as pd
+import pvlib
+from demandlib import bdew
+
+warnings.resetwarnings() # Reset to default behavior due to weird dependency behaviour
+
+# Data directory
+DATA_DIR = Path(__file__).parent / 'raw'
+
+
+# === Data Loading ===
+
+
+def load_weather() -> pd.DataFrame:
+ """Load PVGIS TMY weather data for Dresden.
+
+ Returns
+ -------
+ pd.DataFrame
+ Hourly weather data with columns:
+ - temperature_C: Ambient temperature (Β°C)
+ - ghi_W_m2: Global horizontal irradiance (W/mΒ²)
+ - dni_W_m2: Direct normal irradiance (W/mΒ²)
+ - dhi_W_m2: Diffuse horizontal irradiance (W/mΒ²)
+ - wind_speed_m_s: Wind speed at 10m (m/s)
+ """
+ return pd.read_csv(DATA_DIR / 'tmy_dresden.csv', parse_dates=['time'], index_col='time')
+
+
+def load_electricity_prices() -> pd.Series:
+ """Load German day-ahead electricity prices (2020).
+
+ Returns
+ -------
+ pd.Series
+ Hourly electricity prices in EUR/MWh
+ """
+ df = pd.read_csv(DATA_DIR / 'electricity_prices_de_2020.csv', parse_dates=['time'], index_col='time')
+ return df['price_eur_mwh']
+
+
+# === Profile Generators ===
+
+
+class ThermalLoadGenerator:
+ """Generate thermal load profiles using BDEW standard load profiles.
+
+ Uses demandlib to create realistic heat demand profiles based on
+ German BDEW (Bundesverband der Energie- und Wasserwirtschaft) standards.
+ """
+
+ BUILDING_TYPES = {
+ 'residential': {'shlp_type': 'EFH', 'building_class': 5}, # Single-family house
+ 'residential_multi': {'shlp_type': 'MFH', 'building_class': 5}, # Multi-family
+ 'office': {'shlp_type': 'GKO', 'building_class': 0}, # Commercial office
+ 'retail': {'shlp_type': 'GHA', 'building_class': 0}, # Retail/shops
+ 'industrial': {'shlp_type': 'GMK', 'building_class': 0}, # Industrial
+ }
+
+ def __init__(self, year: int = 2020):
+ self.year = year
+ self.holidays = holidays.Germany(years=year)
+
+ def generate(
+ self,
+ timesteps: pd.DatetimeIndex,
+ temperature: np.ndarray | pd.Series,
+ building_type: str = 'residential',
+ annual_demand_kwh: float = 20000,
+ ) -> np.ndarray:
+ """Generate thermal load profile.
+
+ Parameters
+ ----------
+ timesteps
+ Time index for the profile
+ temperature
+ Ambient temperature in Celsius (same length as timesteps)
+ building_type
+ One of: 'residential', 'residential_multi', 'office', 'retail', 'industrial'
+ annual_demand_kwh
+ Total annual heat demand in kWh
+
+ Returns
+ -------
+ np.ndarray
+ Heat demand profile in kW
+ """
+ params = self.BUILDING_TYPES[building_type]
+ temp_series = pd.Series(temperature, index=timesteps)
+
+ profile = bdew.HeatBuilding(
+ timesteps,
+ holidays=self.holidays,
+ temperature=temp_series,
+ shlp_type=params['shlp_type'],
+ building_class=params['building_class'],
+ wind_class=0,
+ annual_heat_demand=annual_demand_kwh,
+ name=building_type,
+ )
+ return profile.get_bdew_profile().values
+
+
+class ElectricityLoadGenerator:
+ """Generate electricity load profiles using BDEW standard load profiles."""
+
+ CONSUMER_TYPES = {
+ 'household': 'h0',
+ 'commercial': 'g0',
+ 'commercial_office': 'g1',
+ 'commercial_retail': 'g4',
+ 'agricultural': 'l0',
+ }
+
+ def __init__(self, year: int = 2020):
+ self.year = year
+ self.holidays = holidays.Germany(years=year)
+
+ def generate(
+ self,
+ timesteps: pd.DatetimeIndex,
+ consumer_type: str = 'household',
+ annual_demand_kwh: float = 4000,
+ ) -> np.ndarray:
+ """Generate electricity load profile.
+
+ Parameters
+ ----------
+ timesteps
+ Time index for the profile
+ consumer_type
+ One of: 'household', 'commercial', 'commercial_office', 'commercial_retail', 'agricultural'
+ annual_demand_kwh
+ Total annual electricity demand in kWh
+
+ Returns
+ -------
+ np.ndarray
+ Electricity demand profile in kW
+ """
+ slp_type = self.CONSUMER_TYPES[consumer_type]
+ e_slp = bdew.ElecSlp(self.year, holidays=self.holidays)
+ profile = e_slp.get_scaled_power_profiles({slp_type: annual_demand_kwh})
+ # Resample to hourly and align with requested timesteps
+ profile_hourly = profile[slp_type].resample('h').mean()
+ return profile_hourly.reindex(timesteps, method='ffill').values
+
+
+class SolarGenerator:
+ """Generate solar irradiance and PV generation profiles using pvlib.
+
+ Uses Dresden location (51.05Β°N, 13.74Β°E) as default.
+ """
+
+ def __init__(self, latitude: float = 51.05, longitude: float = 13.74):
+ self.location = pvlib.location.Location(latitude, longitude, 'Europe/Berlin', 120, 'Dresden')
+
+ def generate_pv_profile(
+ self,
+ timesteps: pd.DatetimeIndex,
+ weather: pd.DataFrame,
+ surface_tilt: float = 35,
+ surface_azimuth: float = 180, # South-facing
+ capacity_kw: float = 1.0,
+ ) -> np.ndarray:
+ """Generate PV power output profile.
+
+ Parameters
+ ----------
+ timesteps
+ Time index for the profile
+ weather
+ Weather data with 'ghi_W_m2', 'dni_W_m2', 'dhi_W_m2', 'temperature_C'
+ surface_tilt
+ Panel tilt angle in degrees (0=horizontal, 90=vertical)
+ surface_azimuth
+ Panel azimuth in degrees (180=south, 90=east, 270=west)
+ capacity_kw
+ Installed PV capacity in kW
+
+ Returns
+ -------
+ np.ndarray
+ PV power output in kW
+ """
+ # Ensure weather is aligned with timesteps
+ weather = weather.reindex(timesteps, method='ffill')
+
+ # Get solar position
+ solar_position = self.location.get_solarposition(timesteps)
+
+ # Calculate plane-of-array irradiance
+ poa = pvlib.irradiance.get_total_irradiance(
+ surface_tilt=surface_tilt,
+ surface_azimuth=surface_azimuth,
+ solar_zenith=solar_position['apparent_zenith'],
+ solar_azimuth=solar_position['azimuth'],
+ dni=weather['dni_W_m2'],
+ ghi=weather['ghi_W_m2'],
+ dhi=weather['dhi_W_m2'],
+ )
+
+ # Simple efficiency model: ~15% module efficiency, ~85% system efficiency
+ system_efficiency = 0.15 * 0.85
+ pv_output = poa['poa_global'] * system_efficiency * capacity_kw / 1000
+
+ return np.clip(pv_output.fillna(0).values, 0, capacity_kw)
+
+
+class GasPriceGenerator:
+ """Generate synthetic gas price profiles with seasonal variation."""
+
+ def generate(
+ self,
+ timesteps: pd.DatetimeIndex,
+ base_price: float = 35,
+ winter_premium: float = 10,
+ ) -> np.ndarray:
+ """Generate gas price profile.
+
+ Parameters
+ ----------
+ timesteps
+ Time index for the profile
+ base_price
+ Base gas price in EUR/MWh
+ winter_premium
+ Additional winter price in EUR/MWh
+
+ Returns
+ -------
+ np.ndarray
+ Gas prices in EUR/MWh
+ """
+ day_of_year = timesteps.dayofyear.values
+ # Peak in mid-January (day 15), trough in mid-July
+ seasonal = winter_premium * np.cos(2 * np.pi * (day_of_year - 15) / 365)
+ return base_price + seasonal
diff --git a/docs/notebooks/data/raw/README.md b/docs/notebooks/data/raw/README.md
new file mode 100644
index 000000000..37c83b1e5
--- /dev/null
+++ b/docs/notebooks/data/raw/README.md
@@ -0,0 +1,31 @@
+# Bundled Data Sources
+
+## Weather Data (TMY)
+
+**File:** `tmy_dresden.csv`
+**Location:** Dresden, Germany (51.05Β°N, 13.74Β°E)
+**Source:** PVGIS - Photovoltaic Geographical Information System
+**Provider:** European Commission Joint Research Centre
+**License:** Free for any use
+**URL:** https://re.jrc.ec.europa.eu/pvg_tools/en/
+
+**Columns:**
+- `temperature_C`: 2m air temperature (Β°C)
+- `ghi_W_m2`: Global horizontal irradiance (W/mΒ²)
+- `dni_W_m2`: Direct normal irradiance (W/mΒ²)
+- `dhi_W_m2`: Diffuse horizontal irradiance (W/mΒ²)
+- `wind_speed_m_s`: Wind speed at 10m (m/s)
+- `relative_humidity_percent`: Relative humidity (%)
+
+## Electricity Prices
+
+**File:** `electricity_prices_de_2020.csv`
+**Coverage:** Germany, Jan-Sep 2020, hourly
+**Source:** Open Power System Data
+**License:** Open Database License (ODbL)
+**URL:** https://data.open-power-system-data.org/time_series/
+
+**Attribution required:** "Data from Open Power System Data. https://open-power-system-data.org"
+
+**Columns:**
+- `price_eur_mwh`: Day-ahead electricity price (EUR/MWh)
diff --git a/docs/notebooks/data/raw/electricity_prices_de_2020.csv b/docs/notebooks/data/raw/electricity_prices_de_2020.csv
new file mode 100644
index 000000000..25a0f2e24
--- /dev/null
+++ b/docs/notebooks/data/raw/electricity_prices_de_2020.csv
@@ -0,0 +1,6574 @@
+time,price_eur_mwh
+2020-01-01 00:00:00+00:00,38.6
+2020-01-01 01:00:00+00:00,36.55
+2020-01-01 02:00:00+00:00,32.32
+2020-01-01 03:00:00+00:00,30.85
+2020-01-01 04:00:00+00:00,30.14
+2020-01-01 05:00:00+00:00,30.17
+2020-01-01 06:00:00+00:00,30.0
+2020-01-01 07:00:00+00:00,30.65
+2020-01-01 08:00:00+00:00,30.65
+2020-01-01 09:00:00+00:00,30.27
+2020-01-01 10:00:00+00:00,30.34
+2020-01-01 11:00:00+00:00,30.99
+2020-01-01 12:00:00+00:00,30.04
+2020-01-01 13:00:00+00:00,30.75
+2020-01-01 14:00:00+00:00,32.11
+2020-01-01 15:00:00+00:00,35.98
+2020-01-01 16:00:00+00:00,40.4
+2020-01-01 17:00:00+00:00,44.05
+2020-01-01 18:00:00+00:00,43.15
+2020-01-01 19:00:00+00:00,43.45
+2020-01-01 20:00:00+00:00,40.68
+2020-01-01 21:00:00+00:00,40.27
+2020-01-01 22:00:00+00:00,34.85
+2020-01-01 23:00:00+00:00,35.4
+2020-01-02 00:00:00+00:00,31.98
+2020-01-02 01:00:00+00:00,30.5
+2020-01-02 02:00:00+00:00,28.79
+2020-01-02 03:00:00+00:00,28.42
+2020-01-02 04:00:00+00:00,28.75
+2020-01-02 05:00:00+00:00,34.16
+2020-01-02 06:00:00+00:00,42.07
+2020-01-02 07:00:00+00:00,44.89
+2020-01-02 08:00:00+00:00,45.26
+2020-01-02 09:00:00+00:00,45.57
+2020-01-02 10:00:00+00:00,45.09
+2020-01-02 11:00:00+00:00,45.16
+2020-01-02 12:00:00+00:00,44.9
+2020-01-02 13:00:00+00:00,44.06
+2020-01-02 14:00:00+00:00,44.84
+2020-01-02 15:00:00+00:00,44.4
+2020-01-02 16:00:00+00:00,46.05
+2020-01-02 17:00:00+00:00,46.72
+2020-01-02 18:00:00+00:00,45.26
+2020-01-02 19:00:00+00:00,39.32
+2020-01-02 20:00:00+00:00,34.06
+2020-01-02 21:00:00+00:00,32.22
+2020-01-02 22:00:00+00:00,24.99
+2020-01-02 23:00:00+00:00,21.47
+2020-01-03 00:00:00+00:00,13.04
+2020-01-03 01:00:00+00:00,1.53
+2020-01-03 02:00:00+00:00,0.14
+2020-01-03 03:00:00+00:00,0.85
+2020-01-03 04:00:00+00:00,9.92
+2020-01-03 05:00:00+00:00,24.48
+2020-01-03 06:00:00+00:00,26.68
+2020-01-03 07:00:00+00:00,28.81
+2020-01-03 08:00:00+00:00,29.28
+2020-01-03 09:00:00+00:00,28.85
+2020-01-03 10:00:00+00:00,31.8
+2020-01-03 11:00:00+00:00,37.94
+2020-01-03 12:00:00+00:00,37.9
+2020-01-03 13:00:00+00:00,38.11
+2020-01-03 14:00:00+00:00,37.91
+2020-01-03 15:00:00+00:00,38.44
+2020-01-03 16:00:00+00:00,40.47
+2020-01-03 17:00:00+00:00,41.35
+2020-01-03 18:00:00+00:00,33.37
+2020-01-03 19:00:00+00:00,28.89
+2020-01-03 20:00:00+00:00,27.7
+2020-01-03 21:00:00+00:00,25.7
+2020-01-03 22:00:00+00:00,22.04
+2020-01-03 23:00:00+00:00,22.9
+2020-01-04 00:00:00+00:00,15.95
+2020-01-04 01:00:00+00:00,16.63
+2020-01-04 02:00:00+00:00,6.45
+2020-01-04 03:00:00+00:00,3.83
+2020-01-04 04:00:00+00:00,0.12
+2020-01-04 05:00:00+00:00,0.07
+2020-01-04 06:00:00+00:00,19.07
+2020-01-04 07:00:00+00:00,17.49
+2020-01-04 08:00:00+00:00,23.98
+2020-01-04 09:00:00+00:00,8.8
+2020-01-04 10:00:00+00:00,17.95
+2020-01-04 11:00:00+00:00,19.5
+2020-01-04 12:00:00+00:00,13.74
+2020-01-04 13:00:00+00:00,17.42
+2020-01-04 14:00:00+00:00,20.38
+2020-01-04 15:00:00+00:00,25.08
+2020-01-04 16:00:00+00:00,28.88
+2020-01-04 17:00:00+00:00,32.02
+2020-01-04 18:00:00+00:00,35.35
+2020-01-04 19:00:00+00:00,29.98
+2020-01-04 20:00:00+00:00,34.46
+2020-01-04 21:00:00+00:00,39.75
+2020-01-04 22:00:00+00:00,37.95
+2020-01-04 23:00:00+00:00,33.1
+2020-01-05 00:00:00+00:00,32.28
+2020-01-05 01:00:00+00:00,31.18
+2020-01-05 02:00:00+00:00,30.1
+2020-01-05 03:00:00+00:00,29.96
+2020-01-05 04:00:00+00:00,29.88
+2020-01-05 05:00:00+00:00,30.38
+2020-01-05 06:00:00+00:00,31.15
+2020-01-05 07:00:00+00:00,32.09
+2020-01-05 08:00:00+00:00,34.27
+2020-01-05 09:00:00+00:00,37.53
+2020-01-05 10:00:00+00:00,38.99
+2020-01-05 11:00:00+00:00,38.15
+2020-01-05 12:00:00+00:00,35.37
+2020-01-05 13:00:00+00:00,34.44
+2020-01-05 14:00:00+00:00,36.1
+2020-01-05 15:00:00+00:00,40.59
+2020-01-05 16:00:00+00:00,44.68
+2020-01-05 17:00:00+00:00,46.16
+2020-01-05 18:00:00+00:00,44.62
+2020-01-05 19:00:00+00:00,39.5
+2020-01-05 20:00:00+00:00,35.76
+2020-01-05 21:00:00+00:00,36.49
+2020-01-05 22:00:00+00:00,30.49
+2020-01-05 23:00:00+00:00,29.16
+2020-01-06 00:00:00+00:00,29.0
+2020-01-06 01:00:00+00:00,29.08
+2020-01-06 02:00:00+00:00,27.72
+2020-01-06 03:00:00+00:00,27.03
+2020-01-06 04:00:00+00:00,28.98
+2020-01-06 05:00:00+00:00,33.18
+2020-01-06 06:00:00+00:00,43.13
+2020-01-06 07:00:00+00:00,44.52
+2020-01-06 08:00:00+00:00,44.96
+2020-01-06 09:00:00+00:00,44.0
+2020-01-06 10:00:00+00:00,42.46
+2020-01-06 11:00:00+00:00,41.3
+2020-01-06 12:00:00+00:00,40.51
+2020-01-06 13:00:00+00:00,41.22
+2020-01-06 14:00:00+00:00,43.28
+2020-01-06 15:00:00+00:00,43.68
+2020-01-06 16:00:00+00:00,47.9
+2020-01-06 17:00:00+00:00,48.91
+2020-01-06 18:00:00+00:00,45.04
+2020-01-06 19:00:00+00:00,40.28
+2020-01-06 20:00:00+00:00,33.89
+2020-01-06 21:00:00+00:00,33.58
+2020-01-06 22:00:00+00:00,32.41
+2020-01-06 23:00:00+00:00,30.75
+2020-01-07 00:00:00+00:00,31.03
+2020-01-07 01:00:00+00:00,29.88
+2020-01-07 02:00:00+00:00,29.0
+2020-01-07 03:00:00+00:00,29.65
+2020-01-07 04:00:00+00:00,31.78
+2020-01-07 05:00:00+00:00,40.87
+2020-01-07 06:00:00+00:00,49.01
+2020-01-07 07:00:00+00:00,51.09
+2020-01-07 08:00:00+00:00,51.12
+2020-01-07 09:00:00+00:00,49.83
+2020-01-07 10:00:00+00:00,49.16
+2020-01-07 11:00:00+00:00,48.43
+2020-01-07 12:00:00+00:00,47.99
+2020-01-07 13:00:00+00:00,47.41
+2020-01-07 14:00:00+00:00,45.87
+2020-01-07 15:00:00+00:00,45.9
+2020-01-07 16:00:00+00:00,47.96
+2020-01-07 17:00:00+00:00,48.11
+2020-01-07 18:00:00+00:00,43.63
+2020-01-07 19:00:00+00:00,33.6
+2020-01-07 20:00:00+00:00,32.93
+2020-01-07 21:00:00+00:00,31.29
+2020-01-07 22:00:00+00:00,26.28
+2020-01-07 23:00:00+00:00,18.95
+2020-01-08 00:00:00+00:00,4.96
+2020-01-08 01:00:00+00:00,0.1
+2020-01-08 02:00:00+00:00,0.11
+2020-01-08 03:00:00+00:00,1.75
+2020-01-08 04:00:00+00:00,20.74
+2020-01-08 05:00:00+00:00,25.57
+2020-01-08 06:00:00+00:00,32.47
+2020-01-08 07:00:00+00:00,33.07
+2020-01-08 08:00:00+00:00,33.05
+2020-01-08 09:00:00+00:00,34.18
+2020-01-08 10:00:00+00:00,39.63
+2020-01-08 11:00:00+00:00,41.35
+2020-01-08 12:00:00+00:00,44.83
+2020-01-08 13:00:00+00:00,46.04
+2020-01-08 14:00:00+00:00,46.33
+2020-01-08 15:00:00+00:00,47.9
+2020-01-08 16:00:00+00:00,51.21
+2020-01-08 17:00:00+00:00,55.92
+2020-01-08 18:00:00+00:00,53.69
+2020-01-08 19:00:00+00:00,48.1
+2020-01-08 20:00:00+00:00,44.92
+2020-01-08 21:00:00+00:00,41.67
+2020-01-08 22:00:00+00:00,39.41
+2020-01-08 23:00:00+00:00,34.08
+2020-01-09 00:00:00+00:00,32.2
+2020-01-09 01:00:00+00:00,32.56
+2020-01-09 02:00:00+00:00,32.35
+2020-01-09 03:00:00+00:00,29.0
+2020-01-09 04:00:00+00:00,30.86
+2020-01-09 05:00:00+00:00,38.95
+2020-01-09 06:00:00+00:00,46.86
+2020-01-09 07:00:00+00:00,47.92
+2020-01-09 08:00:00+00:00,45.68
+2020-01-09 09:00:00+00:00,43.61
+2020-01-09 10:00:00+00:00,40.0
+2020-01-09 11:00:00+00:00,37.06
+2020-01-09 12:00:00+00:00,33.45
+2020-01-09 13:00:00+00:00,32.2
+2020-01-09 14:00:00+00:00,31.86
+2020-01-09 15:00:00+00:00,32.59
+2020-01-09 16:00:00+00:00,42.85
+2020-01-09 17:00:00+00:00,41.73
+2020-01-09 18:00:00+00:00,40.31
+2020-01-09 19:00:00+00:00,32.96
+2020-01-09 20:00:00+00:00,30.72
+2020-01-09 21:00:00+00:00,31.02
+2020-01-09 22:00:00+00:00,29.14
+2020-01-09 23:00:00+00:00,26.94
+2020-01-10 00:00:00+00:00,26.59
+2020-01-10 01:00:00+00:00,25.81
+2020-01-10 02:00:00+00:00,25.89
+2020-01-10 03:00:00+00:00,26.2
+2020-01-10 04:00:00+00:00,26.95
+2020-01-10 05:00:00+00:00,28.95
+2020-01-10 06:00:00+00:00,43.29
+2020-01-10 07:00:00+00:00,47.4
+2020-01-10 08:00:00+00:00,40.63
+2020-01-10 09:00:00+00:00,36.26
+2020-01-10 10:00:00+00:00,32.05
+2020-01-10 11:00:00+00:00,28.64
+2020-01-10 12:00:00+00:00,28.45
+2020-01-10 13:00:00+00:00,28.23
+2020-01-10 14:00:00+00:00,29.56
+2020-01-10 15:00:00+00:00,36.43
+2020-01-10 16:00:00+00:00,45.0
+2020-01-10 17:00:00+00:00,46.73
+2020-01-10 18:00:00+00:00,45.94
+2020-01-10 19:00:00+00:00,45.02
+2020-01-10 20:00:00+00:00,41.29
+2020-01-10 21:00:00+00:00,39.9
+2020-01-10 22:00:00+00:00,33.04
+2020-01-10 23:00:00+00:00,35.01
+2020-01-11 00:00:00+00:00,34.0
+2020-01-11 01:00:00+00:00,31.43
+2020-01-11 02:00:00+00:00,29.14
+2020-01-11 03:00:00+00:00,28.86
+2020-01-11 04:00:00+00:00,28.43
+2020-01-11 05:00:00+00:00,29.22
+2020-01-11 06:00:00+00:00,31.22
+2020-01-11 07:00:00+00:00,35.68
+2020-01-11 08:00:00+00:00,40.0
+2020-01-11 09:00:00+00:00,38.01
+2020-01-11 10:00:00+00:00,37.9
+2020-01-11 11:00:00+00:00,36.08
+2020-01-11 12:00:00+00:00,32.96
+2020-01-11 13:00:00+00:00,31.1
+2020-01-11 14:00:00+00:00,32.25
+2020-01-11 15:00:00+00:00,32.55
+2020-01-11 16:00:00+00:00,40.56
+2020-01-11 17:00:00+00:00,34.46
+2020-01-11 18:00:00+00:00,30.01
+2020-01-11 19:00:00+00:00,25.74
+2020-01-11 20:00:00+00:00,23.73
+2020-01-11 21:00:00+00:00,25.24
+2020-01-11 22:00:00+00:00,20.96
+2020-01-11 23:00:00+00:00,22.82
+2020-01-12 00:00:00+00:00,19.37
+2020-01-12 01:00:00+00:00,18.36
+2020-01-12 02:00:00+00:00,18.34
+2020-01-12 03:00:00+00:00,18.16
+2020-01-12 04:00:00+00:00,18.66
+2020-01-12 05:00:00+00:00,17.39
+2020-01-12 06:00:00+00:00,18.22
+2020-01-12 07:00:00+00:00,22.1
+2020-01-12 08:00:00+00:00,23.93
+2020-01-12 09:00:00+00:00,24.23
+2020-01-12 10:00:00+00:00,24.84
+2020-01-12 11:00:00+00:00,24.45
+2020-01-12 12:00:00+00:00,22.46
+2020-01-12 13:00:00+00:00,20.05
+2020-01-12 14:00:00+00:00,21.48
+2020-01-12 15:00:00+00:00,24.71
+2020-01-12 16:00:00+00:00,26.5
+2020-01-12 17:00:00+00:00,26.68
+2020-01-12 18:00:00+00:00,26.16
+2020-01-12 19:00:00+00:00,25.62
+2020-01-12 20:00:00+00:00,25.53
+2020-01-12 21:00:00+00:00,27.1
+2020-01-12 22:00:00+00:00,26.14
+2020-01-12 23:00:00+00:00,21.82
+2020-01-13 00:00:00+00:00,23.98
+2020-01-13 01:00:00+00:00,25.23
+2020-01-13 02:00:00+00:00,24.85
+2020-01-13 03:00:00+00:00,25.01
+2020-01-13 04:00:00+00:00,27.32
+2020-01-13 05:00:00+00:00,38.4
+2020-01-13 06:00:00+00:00,48.64
+2020-01-13 07:00:00+00:00,52.93
+2020-01-13 08:00:00+00:00,49.89
+2020-01-13 09:00:00+00:00,48.89
+2020-01-13 10:00:00+00:00,47.2
+2020-01-13 11:00:00+00:00,47.0
+2020-01-13 12:00:00+00:00,45.95
+2020-01-13 13:00:00+00:00,45.0
+2020-01-13 14:00:00+00:00,45.96
+2020-01-13 15:00:00+00:00,43.68
+2020-01-13 16:00:00+00:00,46.81
+2020-01-13 17:00:00+00:00,45.27
+2020-01-13 18:00:00+00:00,42.55
+2020-01-13 19:00:00+00:00,31.9
+2020-01-13 20:00:00+00:00,26.68
+2020-01-13 21:00:00+00:00,25.96
+2020-01-13 22:00:00+00:00,23.4
+2020-01-13 23:00:00+00:00,22.59
+2020-01-14 00:00:00+00:00,16.5
+2020-01-14 01:00:00+00:00,8.89
+2020-01-14 02:00:00+00:00,1.52
+2020-01-14 03:00:00+00:00,1.58
+2020-01-14 04:00:00+00:00,14.13
+2020-01-14 05:00:00+00:00,25.23
+2020-01-14 06:00:00+00:00,27.13
+2020-01-14 07:00:00+00:00,28.55
+2020-01-14 08:00:00+00:00,27.68
+2020-01-14 09:00:00+00:00,27.42
+2020-01-14 10:00:00+00:00,27.43
+2020-01-14 11:00:00+00:00,27.68
+2020-01-14 12:00:00+00:00,29.56
+2020-01-14 13:00:00+00:00,32.0
+2020-01-14 14:00:00+00:00,32.74
+2020-01-14 15:00:00+00:00,30.38
+2020-01-14 16:00:00+00:00,38.0
+2020-01-14 17:00:00+00:00,30.32
+2020-01-14 18:00:00+00:00,26.94
+2020-01-14 19:00:00+00:00,25.74
+2020-01-14 20:00:00+00:00,23.82
+2020-01-14 21:00:00+00:00,22.3
+2020-01-14 22:00:00+00:00,12.4
+2020-01-14 23:00:00+00:00,16.14
+2020-01-15 00:00:00+00:00,5.06
+2020-01-15 01:00:00+00:00,0.11
+2020-01-15 02:00:00+00:00,1.77
+2020-01-15 03:00:00+00:00,7.13
+2020-01-15 04:00:00+00:00,17.86
+2020-01-15 05:00:00+00:00,25.18
+2020-01-15 06:00:00+00:00,35.52
+2020-01-15 07:00:00+00:00,36.56
+2020-01-15 08:00:00+00:00,33.33
+2020-01-15 09:00:00+00:00,25.34
+2020-01-15 10:00:00+00:00,24.98
+2020-01-15 11:00:00+00:00,25.05
+2020-01-15 12:00:00+00:00,25.12
+2020-01-15 13:00:00+00:00,25.24
+2020-01-15 14:00:00+00:00,30.17
+2020-01-15 15:00:00+00:00,29.98
+2020-01-15 16:00:00+00:00,36.49
+2020-01-15 17:00:00+00:00,35.46
+2020-01-15 18:00:00+00:00,35.28
+2020-01-15 19:00:00+00:00,33.65
+2020-01-15 20:00:00+00:00,29.57
+2020-01-15 21:00:00+00:00,33.59
+2020-01-15 22:00:00+00:00,30.46
+2020-01-15 23:00:00+00:00,28.38
+2020-01-16 00:00:00+00:00,30.26
+2020-01-16 01:00:00+00:00,29.92
+2020-01-16 02:00:00+00:00,29.39
+2020-01-16 03:00:00+00:00,29.64
+2020-01-16 04:00:00+00:00,31.1
+2020-01-16 05:00:00+00:00,39.04
+2020-01-16 06:00:00+00:00,45.42
+2020-01-16 07:00:00+00:00,52.4
+2020-01-16 08:00:00+00:00,47.0
+2020-01-16 09:00:00+00:00,43.51
+2020-01-16 10:00:00+00:00,42.1
+2020-01-16 11:00:00+00:00,40.36
+2020-01-16 12:00:00+00:00,41.16
+2020-01-16 13:00:00+00:00,42.91
+2020-01-16 14:00:00+00:00,46.0
+2020-01-16 15:00:00+00:00,46.45
+2020-01-16 16:00:00+00:00,44.61
+2020-01-16 17:00:00+00:00,43.15
+2020-01-16 18:00:00+00:00,38.86
+2020-01-16 19:00:00+00:00,33.42
+2020-01-16 20:00:00+00:00,30.8
+2020-01-16 21:00:00+00:00,31.56
+2020-01-16 22:00:00+00:00,28.64
+2020-01-16 23:00:00+00:00,27.36
+2020-01-17 00:00:00+00:00,27.16
+2020-01-17 01:00:00+00:00,26.58
+2020-01-17 02:00:00+00:00,25.71
+2020-01-17 03:00:00+00:00,26.01
+2020-01-17 04:00:00+00:00,27.97
+2020-01-17 05:00:00+00:00,31.09
+2020-01-17 06:00:00+00:00,40.2
+2020-01-17 07:00:00+00:00,43.8
+2020-01-17 08:00:00+00:00,42.94
+2020-01-17 09:00:00+00:00,42.34
+2020-01-17 10:00:00+00:00,40.79
+2020-01-17 11:00:00+00:00,41.04
+2020-01-17 12:00:00+00:00,39.94
+2020-01-17 13:00:00+00:00,39.02
+2020-01-17 14:00:00+00:00,43.01
+2020-01-17 15:00:00+00:00,42.8
+2020-01-17 16:00:00+00:00,45.79
+2020-01-17 17:00:00+00:00,46.0
+2020-01-17 18:00:00+00:00,44.66
+2020-01-17 19:00:00+00:00,40.99
+2020-01-17 20:00:00+00:00,33.9
+2020-01-17 21:00:00+00:00,33.38
+2020-01-17 22:00:00+00:00,33.0
+2020-01-17 23:00:00+00:00,22.15
+2020-01-18 00:00:00+00:00,24.86
+2020-01-18 01:00:00+00:00,22.24
+2020-01-18 02:00:00+00:00,25.36
+2020-01-18 03:00:00+00:00,25.39
+2020-01-18 04:00:00+00:00,25.96
+2020-01-18 05:00:00+00:00,22.99
+2020-01-18 06:00:00+00:00,28.46
+2020-01-18 07:00:00+00:00,28.1
+2020-01-18 08:00:00+00:00,37.73
+2020-01-18 09:00:00+00:00,35.21
+2020-01-18 10:00:00+00:00,33.34
+2020-01-18 11:00:00+00:00,29.2
+2020-01-18 12:00:00+00:00,31.55
+2020-01-18 13:00:00+00:00,34.78
+2020-01-18 14:00:00+00:00,35.09
+2020-01-18 15:00:00+00:00,37.27
+2020-01-18 16:00:00+00:00,41.3
+2020-01-18 17:00:00+00:00,43.04
+2020-01-18 18:00:00+00:00,41.91
+2020-01-18 19:00:00+00:00,38.59
+2020-01-18 20:00:00+00:00,35.13
+2020-01-18 21:00:00+00:00,33.48
+2020-01-18 22:00:00+00:00,31.22
+2020-01-18 23:00:00+00:00,33.1
+2020-01-19 00:00:00+00:00,30.67
+2020-01-19 01:00:00+00:00,29.47
+2020-01-19 02:00:00+00:00,28.79
+2020-01-19 03:00:00+00:00,27.71
+2020-01-19 04:00:00+00:00,27.26
+2020-01-19 05:00:00+00:00,27.82
+2020-01-19 06:00:00+00:00,30.01
+2020-01-19 07:00:00+00:00,31.47
+2020-01-19 08:00:00+00:00,35.2
+2020-01-19 09:00:00+00:00,35.2
+2020-01-19 10:00:00+00:00,34.47
+2020-01-19 11:00:00+00:00,33.36
+2020-01-19 12:00:00+00:00,29.9
+2020-01-19 13:00:00+00:00,29.92
+2020-01-19 14:00:00+00:00,30.86
+2020-01-19 15:00:00+00:00,33.07
+2020-01-19 16:00:00+00:00,42.98
+2020-01-19 17:00:00+00:00,44.24
+2020-01-19 18:00:00+00:00,43.89
+2020-01-19 19:00:00+00:00,41.14
+2020-01-19 20:00:00+00:00,36.74
+2020-01-19 21:00:00+00:00,40.0
+2020-01-19 22:00:00+00:00,36.15
+2020-01-19 23:00:00+00:00,34.24
+2020-01-20 00:00:00+00:00,34.01
+2020-01-20 01:00:00+00:00,33.08
+2020-01-20 02:00:00+00:00,32.1
+2020-01-20 03:00:00+00:00,31.5
+2020-01-20 04:00:00+00:00,34.23
+2020-01-20 05:00:00+00:00,45.63
+2020-01-20 06:00:00+00:00,55.97
+2020-01-20 07:00:00+00:00,60.0
+2020-01-20 08:00:00+00:00,57.01
+2020-01-20 09:00:00+00:00,50.63
+2020-01-20 10:00:00+00:00,48.17
+2020-01-20 11:00:00+00:00,43.96
+2020-01-20 12:00:00+00:00,43.02
+2020-01-20 13:00:00+00:00,43.11
+2020-01-20 14:00:00+00:00,44.95
+2020-01-20 15:00:00+00:00,46.0
+2020-01-20 16:00:00+00:00,55.91
+2020-01-20 17:00:00+00:00,57.05
+2020-01-20 18:00:00+00:00,54.02
+2020-01-20 19:00:00+00:00,48.68
+2020-01-20 20:00:00+00:00,41.51
+2020-01-20 21:00:00+00:00,40.0
+2020-01-20 22:00:00+00:00,34.03
+2020-01-20 23:00:00+00:00,33.17
+2020-01-21 00:00:00+00:00,33.01
+2020-01-21 01:00:00+00:00,32.28
+2020-01-21 02:00:00+00:00,32.42
+2020-01-21 03:00:00+00:00,32.9
+2020-01-21 04:00:00+00:00,33.0
+2020-01-21 05:00:00+00:00,37.98
+2020-01-21 06:00:00+00:00,49.77
+2020-01-21 07:00:00+00:00,52.36
+2020-01-21 08:00:00+00:00,48.07
+2020-01-21 09:00:00+00:00,42.1
+2020-01-21 10:00:00+00:00,39.11
+2020-01-21 11:00:00+00:00,37.29
+2020-01-21 12:00:00+00:00,38.1
+2020-01-21 13:00:00+00:00,42.6
+2020-01-21 14:00:00+00:00,47.71
+2020-01-21 15:00:00+00:00,49.97
+2020-01-21 16:00:00+00:00,55.81
+2020-01-21 17:00:00+00:00,55.29
+2020-01-21 18:00:00+00:00,50.7
+2020-01-21 19:00:00+00:00,43.75
+2020-01-21 20:00:00+00:00,40.42
+2020-01-21 21:00:00+00:00,37.52
+2020-01-21 22:00:00+00:00,33.01
+2020-01-21 23:00:00+00:00,34.7
+2020-01-22 00:00:00+00:00,33.87
+2020-01-22 01:00:00+00:00,32.6
+2020-01-22 02:00:00+00:00,32.42
+2020-01-22 03:00:00+00:00,32.64
+2020-01-22 04:00:00+00:00,33.0
+2020-01-22 05:00:00+00:00,39.12
+2020-01-22 06:00:00+00:00,49.26
+2020-01-22 07:00:00+00:00,56.53
+2020-01-22 08:00:00+00:00,50.5
+2020-01-22 09:00:00+00:00,46.27
+2020-01-22 10:00:00+00:00,45.02
+2020-01-22 11:00:00+00:00,42.82
+2020-01-22 12:00:00+00:00,43.45
+2020-01-22 13:00:00+00:00,49.96
+2020-01-22 14:00:00+00:00,52.4
+2020-01-22 15:00:00+00:00,55.63
+2020-01-22 16:00:00+00:00,62.07
+2020-01-22 17:00:00+00:00,65.09
+2020-01-22 18:00:00+00:00,59.58
+2020-01-22 19:00:00+00:00,52.52
+2020-01-22 20:00:00+00:00,47.01
+2020-01-22 21:00:00+00:00,43.99
+2020-01-22 22:00:00+00:00,41.2
+2020-01-22 23:00:00+00:00,40.1
+2020-01-23 00:00:00+00:00,39.23
+2020-01-23 01:00:00+00:00,38.34
+2020-01-23 02:00:00+00:00,36.32
+2020-01-23 03:00:00+00:00,36.6
+2020-01-23 04:00:00+00:00,41.97
+2020-01-23 05:00:00+00:00,47.0
+2020-01-23 06:00:00+00:00,58.74
+2020-01-23 07:00:00+00:00,66.62
+2020-01-23 08:00:00+00:00,64.86
+2020-01-23 09:00:00+00:00,61.68
+2020-01-23 10:00:00+00:00,57.42
+2020-01-23 11:00:00+00:00,55.36
+2020-01-23 12:00:00+00:00,53.68
+2020-01-23 13:00:00+00:00,51.2
+2020-01-23 14:00:00+00:00,53.54
+2020-01-23 15:00:00+00:00,54.75
+2020-01-23 16:00:00+00:00,62.35
+2020-01-23 17:00:00+00:00,68.64
+2020-01-23 18:00:00+00:00,60.4
+2020-01-23 19:00:00+00:00,55.53
+2020-01-23 20:00:00+00:00,47.16
+2020-01-23 21:00:00+00:00,43.9
+2020-01-23 22:00:00+00:00,41.51
+2020-01-23 23:00:00+00:00,36.23
+2020-01-24 00:00:00+00:00,37.6
+2020-01-24 01:00:00+00:00,36.76
+2020-01-24 02:00:00+00:00,35.1
+2020-01-24 03:00:00+00:00,36.47
+2020-01-24 04:00:00+00:00,36.66
+2020-01-24 05:00:00+00:00,44.54
+2020-01-24 06:00:00+00:00,58.29
+2020-01-24 07:00:00+00:00,66.74
+2020-01-24 08:00:00+00:00,65.0
+2020-01-24 09:00:00+00:00,61.12
+2020-01-24 10:00:00+00:00,58.84
+2020-01-24 11:00:00+00:00,56.61
+2020-01-24 12:00:00+00:00,53.29
+2020-01-24 13:00:00+00:00,52.0
+2020-01-24 14:00:00+00:00,53.06
+2020-01-24 15:00:00+00:00,54.01
+2020-01-24 16:00:00+00:00,60.79
+2020-01-24 17:00:00+00:00,65.1
+2020-01-24 18:00:00+00:00,59.79
+2020-01-24 19:00:00+00:00,49.17
+2020-01-24 20:00:00+00:00,44.32
+2020-01-24 21:00:00+00:00,43.7
+2020-01-24 22:00:00+00:00,40.67
+2020-01-24 23:00:00+00:00,36.19
+2020-01-25 00:00:00+00:00,35.09
+2020-01-25 01:00:00+00:00,37.01
+2020-01-25 02:00:00+00:00,35.14
+2020-01-25 03:00:00+00:00,33.11
+2020-01-25 04:00:00+00:00,33.01
+2020-01-25 05:00:00+00:00,34.12
+2020-01-25 06:00:00+00:00,37.1
+2020-01-25 07:00:00+00:00,42.42
+2020-01-25 08:00:00+00:00,44.97
+2020-01-25 09:00:00+00:00,45.96
+2020-01-25 10:00:00+00:00,44.89
+2020-01-25 11:00:00+00:00,43.67
+2020-01-25 12:00:00+00:00,41.14
+2020-01-25 13:00:00+00:00,39.61
+2020-01-25 14:00:00+00:00,41.51
+2020-01-25 15:00:00+00:00,43.53
+2020-01-25 16:00:00+00:00,46.25
+2020-01-25 17:00:00+00:00,49.99
+2020-01-25 18:00:00+00:00,45.84
+2020-01-25 19:00:00+00:00,43.01
+2020-01-25 20:00:00+00:00,38.25
+2020-01-25 21:00:00+00:00,40.57
+2020-01-25 22:00:00+00:00,36.02
+2020-01-25 23:00:00+00:00,34.39
+2020-01-26 00:00:00+00:00,33.64
+2020-01-26 01:00:00+00:00,32.4
+2020-01-26 02:00:00+00:00,29.84
+2020-01-26 03:00:00+00:00,29.33
+2020-01-26 04:00:00+00:00,29.04
+2020-01-26 05:00:00+00:00,30.02
+2020-01-26 06:00:00+00:00,29.49
+2020-01-26 07:00:00+00:00,31.17
+2020-01-26 08:00:00+00:00,34.61
+2020-01-26 09:00:00+00:00,38.92
+2020-01-26 10:00:00+00:00,41.16
+2020-01-26 11:00:00+00:00,41.86
+2020-01-26 12:00:00+00:00,38.23
+2020-01-26 13:00:00+00:00,36.03
+2020-01-26 14:00:00+00:00,34.56
+2020-01-26 15:00:00+00:00,35.81
+2020-01-26 16:00:00+00:00,39.99
+2020-01-26 17:00:00+00:00,42.0
+2020-01-26 18:00:00+00:00,35.47
+2020-01-26 19:00:00+00:00,31.27
+2020-01-26 20:00:00+00:00,27.53
+2020-01-26 21:00:00+00:00,29.09
+2020-01-26 22:00:00+00:00,27.5
+2020-01-26 23:00:00+00:00,28.09
+2020-01-27 00:00:00+00:00,27.73
+2020-01-27 01:00:00+00:00,26.13
+2020-01-27 02:00:00+00:00,23.4
+2020-01-27 03:00:00+00:00,21.98
+2020-01-27 04:00:00+00:00,26.17
+2020-01-27 05:00:00+00:00,28.83
+2020-01-27 06:00:00+00:00,42.2
+2020-01-27 07:00:00+00:00,41.56
+2020-01-27 08:00:00+00:00,40.29
+2020-01-27 09:00:00+00:00,42.71
+2020-01-27 10:00:00+00:00,39.95
+2020-01-27 11:00:00+00:00,38.02
+2020-01-27 12:00:00+00:00,40.72
+2020-01-27 13:00:00+00:00,43.93
+2020-01-27 14:00:00+00:00,45.22
+2020-01-27 15:00:00+00:00,43.17
+2020-01-27 16:00:00+00:00,47.08
+2020-01-27 17:00:00+00:00,51.21
+2020-01-27 18:00:00+00:00,47.12
+2020-01-27 19:00:00+00:00,43.86
+2020-01-27 20:00:00+00:00,40.6
+2020-01-27 21:00:00+00:00,36.61
+2020-01-27 22:00:00+00:00,33.14
+2020-01-27 23:00:00+00:00,27.54
+2020-01-28 00:00:00+00:00,26.84
+2020-01-28 01:00:00+00:00,25.64
+2020-01-28 02:00:00+00:00,24.99
+2020-01-28 03:00:00+00:00,25.17
+2020-01-28 04:00:00+00:00,26.32
+2020-01-28 05:00:00+00:00,31.76
+2020-01-28 06:00:00+00:00,41.94
+2020-01-28 07:00:00+00:00,44.94
+2020-01-28 08:00:00+00:00,44.33
+2020-01-28 09:00:00+00:00,42.9
+2020-01-28 10:00:00+00:00,39.93
+2020-01-28 11:00:00+00:00,33.98
+2020-01-28 12:00:00+00:00,30.0
+2020-01-28 13:00:00+00:00,28.0
+2020-01-28 14:00:00+00:00,27.91
+2020-01-28 15:00:00+00:00,29.68
+2020-01-28 16:00:00+00:00,39.83
+2020-01-28 17:00:00+00:00,39.98
+2020-01-28 18:00:00+00:00,30.62
+2020-01-28 19:00:00+00:00,25.8
+2020-01-28 20:00:00+00:00,25.42
+2020-01-28 21:00:00+00:00,25.04
+2020-01-28 22:00:00+00:00,20.08
+2020-01-28 23:00:00+00:00,20.44
+2020-01-29 00:00:00+00:00,19.58
+2020-01-29 01:00:00+00:00,19.16
+2020-01-29 02:00:00+00:00,19.61
+2020-01-29 03:00:00+00:00,20.46
+2020-01-29 04:00:00+00:00,25.16
+2020-01-29 05:00:00+00:00,29.03
+2020-01-29 06:00:00+00:00,41.12
+2020-01-29 07:00:00+00:00,44.41
+2020-01-29 08:00:00+00:00,41.85
+2020-01-29 09:00:00+00:00,40.82
+2020-01-29 10:00:00+00:00,36.86
+2020-01-29 11:00:00+00:00,31.34
+2020-01-29 12:00:00+00:00,32.4
+2020-01-29 13:00:00+00:00,34.24
+2020-01-29 14:00:00+00:00,37.92
+2020-01-29 15:00:00+00:00,39.02
+2020-01-29 16:00:00+00:00,42.89
+2020-01-29 17:00:00+00:00,45.01
+2020-01-29 18:00:00+00:00,45.1
+2020-01-29 19:00:00+00:00,40.98
+2020-01-29 20:00:00+00:00,33.02
+2020-01-29 21:00:00+00:00,29.63
+2020-01-29 22:00:00+00:00,27.33
+2020-01-29 23:00:00+00:00,28.97
+2020-01-30 00:00:00+00:00,27.43
+2020-01-30 01:00:00+00:00,25.15
+2020-01-30 02:00:00+00:00,20.24
+2020-01-30 03:00:00+00:00,19.91
+2020-01-30 04:00:00+00:00,24.96
+2020-01-30 05:00:00+00:00,29.7
+2020-01-30 06:00:00+00:00,39.46
+2020-01-30 07:00:00+00:00,40.4
+2020-01-30 08:00:00+00:00,37.28
+2020-01-30 09:00:00+00:00,35.9
+2020-01-30 10:00:00+00:00,35.15
+2020-01-30 11:00:00+00:00,36.69
+2020-01-30 12:00:00+00:00,39.79
+2020-01-30 13:00:00+00:00,37.53
+2020-01-30 14:00:00+00:00,35.51
+2020-01-30 15:00:00+00:00,37.85
+2020-01-30 16:00:00+00:00,44.12
+2020-01-30 17:00:00+00:00,43.04
+2020-01-30 18:00:00+00:00,41.1
+2020-01-30 19:00:00+00:00,31.13
+2020-01-30 20:00:00+00:00,29.04
+2020-01-30 21:00:00+00:00,27.3
+2020-01-30 22:00:00+00:00,20.04
+2020-01-30 23:00:00+00:00,-0.04
+2020-01-31 00:00:00+00:00,0.02
+2020-01-31 01:00:00+00:00,-8.77
+2020-01-31 02:00:00+00:00,-3.89
+2020-01-31 03:00:00+00:00,0.01
+2020-01-31 04:00:00+00:00,13.04
+2020-01-31 05:00:00+00:00,24.01
+2020-01-31 06:00:00+00:00,36.96
+2020-01-31 07:00:00+00:00,39.59
+2020-01-31 08:00:00+00:00,37.39
+2020-01-31 09:00:00+00:00,34.9
+2020-01-31 10:00:00+00:00,35.27
+2020-01-31 11:00:00+00:00,27.97
+2020-01-31 12:00:00+00:00,28.84
+2020-01-31 13:00:00+00:00,29.0
+2020-01-31 14:00:00+00:00,30.07
+2020-01-31 15:00:00+00:00,28.1
+2020-01-31 16:00:00+00:00,33.78
+2020-01-31 17:00:00+00:00,37.05
+2020-01-31 18:00:00+00:00,32.58
+2020-01-31 19:00:00+00:00,25.1
+2020-01-31 20:00:00+00:00,21.24
+2020-01-31 21:00:00+00:00,20.29
+2020-01-31 22:00:00+00:00,17.09
+2020-01-31 23:00:00+00:00,0.07
+2020-02-01 00:00:00+00:00,0.02
+2020-02-01 01:00:00+00:00,-0.7
+2020-02-01 02:00:00+00:00,-1.94
+2020-02-01 03:00:00+00:00,-1.67
+2020-02-01 04:00:00+00:00,-2.4
+2020-02-01 05:00:00+00:00,0.04
+2020-02-01 06:00:00+00:00,8.52
+2020-02-01 07:00:00+00:00,14.1
+2020-02-01 08:00:00+00:00,14.7
+2020-02-01 09:00:00+00:00,14.74
+2020-02-01 10:00:00+00:00,14.47
+2020-02-01 11:00:00+00:00,14.07
+2020-02-01 12:00:00+00:00,14.45
+2020-02-01 13:00:00+00:00,13.18
+2020-02-01 14:00:00+00:00,11.11
+2020-02-01 15:00:00+00:00,13.07
+2020-02-01 16:00:00+00:00,16.79
+2020-02-01 17:00:00+00:00,16.97
+2020-02-01 18:00:00+00:00,15.99
+2020-02-01 19:00:00+00:00,0.42
+2020-02-01 20:00:00+00:00,-0.8
+2020-02-01 21:00:00+00:00,0.0
+2020-02-01 22:00:00+00:00,-11.16
+2020-02-01 23:00:00+00:00,-4.97
+2020-02-02 00:00:00+00:00,-10.1
+2020-02-02 01:00:00+00:00,-16.95
+2020-02-02 02:00:00+00:00,-11.7
+2020-02-02 03:00:00+00:00,-5.98
+2020-02-02 04:00:00+00:00,-5.21
+2020-02-02 05:00:00+00:00,-4.98
+2020-02-02 06:00:00+00:00,0.09
+2020-02-02 07:00:00+00:00,13.06
+2020-02-02 08:00:00+00:00,24.5
+2020-02-02 09:00:00+00:00,27.12
+2020-02-02 10:00:00+00:00,29.43
+2020-02-02 11:00:00+00:00,35.0
+2020-02-02 12:00:00+00:00,33.36
+2020-02-02 13:00:00+00:00,33.75
+2020-02-02 14:00:00+00:00,34.2
+2020-02-02 15:00:00+00:00,28.87
+2020-02-02 16:00:00+00:00,40.27
+2020-02-02 17:00:00+00:00,40.73
+2020-02-02 18:00:00+00:00,36.93
+2020-02-02 19:00:00+00:00,27.05
+2020-02-02 20:00:00+00:00,21.99
+2020-02-02 21:00:00+00:00,23.87
+2020-02-02 22:00:00+00:00,17.38
+2020-02-02 23:00:00+00:00,15.92
+2020-02-03 00:00:00+00:00,15.55
+2020-02-03 01:00:00+00:00,14.38
+2020-02-03 02:00:00+00:00,9.32
+2020-02-03 03:00:00+00:00,13.26
+2020-02-03 04:00:00+00:00,14.03
+2020-02-03 05:00:00+00:00,27.06
+2020-02-03 06:00:00+00:00,36.49
+2020-02-03 07:00:00+00:00,39.97
+2020-02-03 08:00:00+00:00,39.26
+2020-02-03 09:00:00+00:00,35.52
+2020-02-03 10:00:00+00:00,32.97
+2020-02-03 11:00:00+00:00,29.08
+2020-02-03 12:00:00+00:00,28.38
+2020-02-03 13:00:00+00:00,28.73
+2020-02-03 14:00:00+00:00,28.29
+2020-02-03 15:00:00+00:00,33.02
+2020-02-03 16:00:00+00:00,37.95
+2020-02-03 17:00:00+00:00,37.99
+2020-02-03 18:00:00+00:00,36.57
+2020-02-03 19:00:00+00:00,31.0
+2020-02-03 20:00:00+00:00,27.16
+2020-02-03 21:00:00+00:00,27.13
+2020-02-03 22:00:00+00:00,24.76
+2020-02-03 23:00:00+00:00,20.79
+2020-02-04 00:00:00+00:00,17.41
+2020-02-04 01:00:00+00:00,16.24
+2020-02-04 02:00:00+00:00,12.96
+2020-02-04 03:00:00+00:00,13.42
+2020-02-04 04:00:00+00:00,15.88
+2020-02-04 05:00:00+00:00,24.88
+2020-02-04 06:00:00+00:00,29.7
+2020-02-04 07:00:00+00:00,35.01
+2020-02-04 08:00:00+00:00,33.48
+2020-02-04 09:00:00+00:00,29.9
+2020-02-04 10:00:00+00:00,29.03
+2020-02-04 11:00:00+00:00,27.07
+2020-02-04 12:00:00+00:00,26.43
+2020-02-04 13:00:00+00:00,27.02
+2020-02-04 14:00:00+00:00,29.05
+2020-02-04 15:00:00+00:00,31.42
+2020-02-04 16:00:00+00:00,39.92
+2020-02-04 17:00:00+00:00,41.3
+2020-02-04 18:00:00+00:00,40.92
+2020-02-04 19:00:00+00:00,39.75
+2020-02-04 20:00:00+00:00,30.13
+2020-02-04 21:00:00+00:00,30.36
+2020-02-04 22:00:00+00:00,26.94
+2020-02-04 23:00:00+00:00,25.44
+2020-02-05 00:00:00+00:00,25.0
+2020-02-05 01:00:00+00:00,24.43
+2020-02-05 02:00:00+00:00,23.63
+2020-02-05 03:00:00+00:00,24.83
+2020-02-05 04:00:00+00:00,26.62
+2020-02-05 05:00:00+00:00,37.54
+2020-02-05 06:00:00+00:00,44.91
+2020-02-05 07:00:00+00:00,49.16
+2020-02-05 08:00:00+00:00,44.78
+2020-02-05 09:00:00+00:00,41.37
+2020-02-05 10:00:00+00:00,40.0
+2020-02-05 11:00:00+00:00,37.07
+2020-02-05 12:00:00+00:00,35.16
+2020-02-05 13:00:00+00:00,35.17
+2020-02-05 14:00:00+00:00,37.13
+2020-02-05 15:00:00+00:00,40.25
+2020-02-05 16:00:00+00:00,45.45
+2020-02-05 17:00:00+00:00,45.83
+2020-02-05 18:00:00+00:00,45.66
+2020-02-05 19:00:00+00:00,41.74
+2020-02-05 20:00:00+00:00,35.92
+2020-02-05 21:00:00+00:00,31.99
+2020-02-05 22:00:00+00:00,29.7
+2020-02-05 23:00:00+00:00,26.51
+2020-02-06 00:00:00+00:00,25.35
+2020-02-06 01:00:00+00:00,24.47
+2020-02-06 02:00:00+00:00,24.44
+2020-02-06 03:00:00+00:00,25.25
+2020-02-06 04:00:00+00:00,27.97
+2020-02-06 05:00:00+00:00,32.96
+2020-02-06 06:00:00+00:00,43.15
+2020-02-06 07:00:00+00:00,44.88
+2020-02-06 08:00:00+00:00,42.9
+2020-02-06 09:00:00+00:00,42.19
+2020-02-06 10:00:00+00:00,40.81
+2020-02-06 11:00:00+00:00,39.25
+2020-02-06 12:00:00+00:00,38.01
+2020-02-06 13:00:00+00:00,37.94
+2020-02-06 14:00:00+00:00,38.06
+2020-02-06 15:00:00+00:00,39.09
+2020-02-06 16:00:00+00:00,45.95
+2020-02-06 17:00:00+00:00,46.83
+2020-02-06 18:00:00+00:00,47.21
+2020-02-06 19:00:00+00:00,43.63
+2020-02-06 20:00:00+00:00,37.98
+2020-02-06 21:00:00+00:00,37.66
+2020-02-06 22:00:00+00:00,33.58
+2020-02-06 23:00:00+00:00,33.32
+2020-02-07 00:00:00+00:00,32.18
+2020-02-07 01:00:00+00:00,32.03
+2020-02-07 02:00:00+00:00,31.44
+2020-02-07 03:00:00+00:00,32.17
+2020-02-07 04:00:00+00:00,33.71
+2020-02-07 05:00:00+00:00,40.68
+2020-02-07 06:00:00+00:00,47.87
+2020-02-07 07:00:00+00:00,56.96
+2020-02-07 08:00:00+00:00,47.0
+2020-02-07 09:00:00+00:00,41.81
+2020-02-07 10:00:00+00:00,38.52
+2020-02-07 11:00:00+00:00,37.78
+2020-02-07 12:00:00+00:00,34.68
+2020-02-07 13:00:00+00:00,33.09
+2020-02-07 14:00:00+00:00,38.29
+2020-02-07 15:00:00+00:00,39.08
+2020-02-07 16:00:00+00:00,40.96
+2020-02-07 17:00:00+00:00,39.93
+2020-02-07 18:00:00+00:00,35.47
+2020-02-07 19:00:00+00:00,32.23
+2020-02-07 20:00:00+00:00,27.93
+2020-02-07 21:00:00+00:00,27.35
+2020-02-07 22:00:00+00:00,26.0
+2020-02-07 23:00:00+00:00,25.21
+2020-02-08 00:00:00+00:00,24.28
+2020-02-08 01:00:00+00:00,23.98
+2020-02-08 02:00:00+00:00,22.9
+2020-02-08 03:00:00+00:00,21.75
+2020-02-08 04:00:00+00:00,20.12
+2020-02-08 05:00:00+00:00,22.34
+2020-02-08 06:00:00+00:00,25.54
+2020-02-08 07:00:00+00:00,28.05
+2020-02-08 08:00:00+00:00,29.07
+2020-02-08 09:00:00+00:00,26.87
+2020-02-08 10:00:00+00:00,26.74
+2020-02-08 11:00:00+00:00,25.0
+2020-02-08 12:00:00+00:00,25.61
+2020-02-08 13:00:00+00:00,26.8
+2020-02-08 14:00:00+00:00,29.92
+2020-02-08 15:00:00+00:00,37.6
+2020-02-08 16:00:00+00:00,39.5
+2020-02-08 17:00:00+00:00,41.3
+2020-02-08 18:00:00+00:00,38.71
+2020-02-08 19:00:00+00:00,31.29
+2020-02-08 20:00:00+00:00,26.84
+2020-02-08 21:00:00+00:00,27.39
+2020-02-08 22:00:00+00:00,26.4
+2020-02-08 23:00:00+00:00,23.06
+2020-02-09 00:00:00+00:00,14.93
+2020-02-09 01:00:00+00:00,12.8
+2020-02-09 02:00:00+00:00,9.18
+2020-02-09 03:00:00+00:00,7.54
+2020-02-09 04:00:00+00:00,4.24
+2020-02-09 05:00:00+00:00,3.85
+2020-02-09 06:00:00+00:00,5.06
+2020-02-09 07:00:00+00:00,1.72
+2020-02-09 08:00:00+00:00,-0.07
+2020-02-09 09:00:00+00:00,-4.94
+2020-02-09 10:00:00+00:00,-3.81
+2020-02-09 11:00:00+00:00,-8.8
+2020-02-09 12:00:00+00:00,-16.95
+2020-02-09 13:00:00+00:00,-13.64
+2020-02-09 14:00:00+00:00,-2.96
+2020-02-09 15:00:00+00:00,-0.1
+2020-02-09 16:00:00+00:00,0.52
+2020-02-09 17:00:00+00:00,11.97
+2020-02-09 18:00:00+00:00,5.22
+2020-02-09 19:00:00+00:00,-4.01
+2020-02-09 20:00:00+00:00,-3.04
+2020-02-09 21:00:00+00:00,-0.08
+2020-02-09 22:00:00+00:00,-4.1
+2020-02-09 23:00:00+00:00,-4.97
+2020-02-10 00:00:00+00:00,-15.89
+2020-02-10 01:00:00+00:00,-15.11
+2020-02-10 02:00:00+00:00,-16.16
+2020-02-10 03:00:00+00:00,-14.93
+2020-02-10 04:00:00+00:00,-2.0
+2020-02-10 05:00:00+00:00,0.41
+2020-02-10 06:00:00+00:00,14.11
+2020-02-10 07:00:00+00:00,21.38
+2020-02-10 08:00:00+00:00,13.2
+2020-02-10 09:00:00+00:00,12.54
+2020-02-10 10:00:00+00:00,12.57
+2020-02-10 11:00:00+00:00,12.01
+2020-02-10 12:00:00+00:00,11.99
+2020-02-10 13:00:00+00:00,11.98
+2020-02-10 14:00:00+00:00,12.24
+2020-02-10 15:00:00+00:00,12.77
+2020-02-10 16:00:00+00:00,23.14
+2020-02-10 17:00:00+00:00,24.96
+2020-02-10 18:00:00+00:00,25.69
+2020-02-10 19:00:00+00:00,19.93
+2020-02-10 20:00:00+00:00,12.47
+2020-02-10 21:00:00+00:00,11.97
+2020-02-10 22:00:00+00:00,4.86
+2020-02-10 23:00:00+00:00,10.96
+2020-02-11 00:00:00+00:00,4.83
+2020-02-11 01:00:00+00:00,0.11
+2020-02-11 02:00:00+00:00,-0.08
+2020-02-11 03:00:00+00:00,-1.86
+2020-02-11 04:00:00+00:00,1.39
+2020-02-11 05:00:00+00:00,11.68
+2020-02-11 06:00:00+00:00,14.95
+2020-02-11 07:00:00+00:00,14.95
+2020-02-11 08:00:00+00:00,13.24
+2020-02-11 09:00:00+00:00,13.11
+2020-02-11 10:00:00+00:00,13.0
+2020-02-11 11:00:00+00:00,12.85
+2020-02-11 12:00:00+00:00,12.77
+2020-02-11 13:00:00+00:00,13.0
+2020-02-11 14:00:00+00:00,12.94
+2020-02-11 15:00:00+00:00,13.67
+2020-02-11 16:00:00+00:00,23.98
+2020-02-11 17:00:00+00:00,24.55
+2020-02-11 18:00:00+00:00,24.54
+2020-02-11 19:00:00+00:00,12.94
+2020-02-11 20:00:00+00:00,12.22
+2020-02-11 21:00:00+00:00,12.04
+2020-02-11 22:00:00+00:00,7.1
+2020-02-11 23:00:00+00:00,3.12
+2020-02-12 00:00:00+00:00,0.88
+2020-02-12 01:00:00+00:00,0.07
+2020-02-12 02:00:00+00:00,0.08
+2020-02-12 03:00:00+00:00,5.29
+2020-02-12 04:00:00+00:00,12.94
+2020-02-12 05:00:00+00:00,20.93
+2020-02-12 06:00:00+00:00,34.24
+2020-02-12 07:00:00+00:00,32.01
+2020-02-12 08:00:00+00:00,24.17
+2020-02-12 09:00:00+00:00,22.31
+2020-02-12 10:00:00+00:00,17.9
+2020-02-12 11:00:00+00:00,13.69
+2020-02-12 12:00:00+00:00,14.02
+2020-02-12 13:00:00+00:00,13.88
+2020-02-12 14:00:00+00:00,22.98
+2020-02-12 15:00:00+00:00,27.87
+2020-02-12 16:00:00+00:00,31.2
+2020-02-12 17:00:00+00:00,37.45
+2020-02-12 18:00:00+00:00,33.19
+2020-02-12 19:00:00+00:00,31.23
+2020-02-12 20:00:00+00:00,26.53
+2020-02-12 21:00:00+00:00,24.16
+2020-02-12 22:00:00+00:00,16.93
+2020-02-12 23:00:00+00:00,25.53
+2020-02-13 00:00:00+00:00,25.91
+2020-02-13 01:00:00+00:00,24.37
+2020-02-13 02:00:00+00:00,24.31
+2020-02-13 03:00:00+00:00,22.8
+2020-02-13 04:00:00+00:00,26.41
+2020-02-13 05:00:00+00:00,39.37
+2020-02-13 06:00:00+00:00,58.88
+2020-02-13 07:00:00+00:00,53.48
+2020-02-13 08:00:00+00:00,48.17
+2020-02-13 09:00:00+00:00,40.5
+2020-02-13 10:00:00+00:00,38.13
+2020-02-13 11:00:00+00:00,36.94
+2020-02-13 12:00:00+00:00,35.97
+2020-02-13 13:00:00+00:00,35.73
+2020-02-13 14:00:00+00:00,36.02
+2020-02-13 15:00:00+00:00,37.76
+2020-02-13 16:00:00+00:00,43.0
+2020-02-13 17:00:00+00:00,53.03
+2020-02-13 18:00:00+00:00,44.83
+2020-02-13 19:00:00+00:00,41.96
+2020-02-13 20:00:00+00:00,39.53
+2020-02-13 21:00:00+00:00,37.93
+2020-02-13 22:00:00+00:00,31.57
+2020-02-13 23:00:00+00:00,27.36
+2020-02-14 00:00:00+00:00,27.09
+2020-02-14 01:00:00+00:00,27.0
+2020-02-14 02:00:00+00:00,25.03
+2020-02-14 03:00:00+00:00,26.2
+2020-02-14 04:00:00+00:00,27.04
+2020-02-14 05:00:00+00:00,38.3
+2020-02-14 06:00:00+00:00,44.86
+2020-02-14 07:00:00+00:00,56.74
+2020-02-14 08:00:00+00:00,49.39
+2020-02-14 09:00:00+00:00,43.93
+2020-02-14 10:00:00+00:00,41.44
+2020-02-14 11:00:00+00:00,39.28
+2020-02-14 12:00:00+00:00,37.19
+2020-02-14 13:00:00+00:00,36.98
+2020-02-14 14:00:00+00:00,37.88
+2020-02-14 15:00:00+00:00,39.25
+2020-02-14 16:00:00+00:00,42.5
+2020-02-14 17:00:00+00:00,43.61
+2020-02-14 18:00:00+00:00,39.31
+2020-02-14 19:00:00+00:00,33.86
+2020-02-14 20:00:00+00:00,28.35
+2020-02-14 21:00:00+00:00,27.05
+2020-02-14 22:00:00+00:00,25.19
+2020-02-14 23:00:00+00:00,28.2
+2020-02-15 00:00:00+00:00,27.06
+2020-02-15 01:00:00+00:00,26.2
+2020-02-15 02:00:00+00:00,24.31
+2020-02-15 03:00:00+00:00,23.2
+2020-02-15 04:00:00+00:00,23.14
+2020-02-15 05:00:00+00:00,20.99
+2020-02-15 06:00:00+00:00,23.19
+2020-02-15 07:00:00+00:00,25.71
+2020-02-15 08:00:00+00:00,31.49
+2020-02-15 09:00:00+00:00,27.41
+2020-02-15 10:00:00+00:00,22.96
+2020-02-15 11:00:00+00:00,21.29
+2020-02-15 12:00:00+00:00,18.83
+2020-02-15 13:00:00+00:00,15.58
+2020-02-15 14:00:00+00:00,22.92
+2020-02-15 15:00:00+00:00,22.99
+2020-02-15 16:00:00+00:00,24.24
+2020-02-15 17:00:00+00:00,25.12
+2020-02-15 18:00:00+00:00,21.8
+2020-02-15 19:00:00+00:00,8.27
+2020-02-15 20:00:00+00:00,1.58
+2020-02-15 21:00:00+00:00,3.97
+2020-02-15 22:00:00+00:00,0.02
+2020-02-15 23:00:00+00:00,-5.9
+2020-02-16 00:00:00+00:00,-8.65
+2020-02-16 01:00:00+00:00,-4.93
+2020-02-16 02:00:00+00:00,-4.99
+2020-02-16 03:00:00+00:00,-5.76
+2020-02-16 04:00:00+00:00,-6.91
+2020-02-16 05:00:00+00:00,-8.51
+2020-02-16 06:00:00+00:00,-4.96
+2020-02-16 07:00:00+00:00,-0.08
+2020-02-16 08:00:00+00:00,-1.36
+2020-02-16 09:00:00+00:00,-8.46
+2020-02-16 10:00:00+00:00,-6.55
+2020-02-16 11:00:00+00:00,-15.24
+2020-02-16 12:00:00+00:00,-20.88
+2020-02-16 13:00:00+00:00,-21.02
+2020-02-16 14:00:00+00:00,-32.14
+2020-02-16 15:00:00+00:00,-19.26
+2020-02-16 16:00:00+00:00,-8.02
+2020-02-16 17:00:00+00:00,-2.5
+2020-02-16 18:00:00+00:00,-3.72
+2020-02-16 19:00:00+00:00,-4.96
+2020-02-16 20:00:00+00:00,-3.39
+2020-02-16 21:00:00+00:00,0.74
+2020-02-16 22:00:00+00:00,-1.13
+2020-02-16 23:00:00+00:00,-25.04
+2020-02-17 00:00:00+00:00,-27.53
+2020-02-17 01:00:00+00:00,-21.99
+2020-02-17 02:00:00+00:00,-12.05
+2020-02-17 03:00:00+00:00,-4.95
+2020-02-17 04:00:00+00:00,-0.08
+2020-02-17 05:00:00+00:00,22.91
+2020-02-17 06:00:00+00:00,30.06
+2020-02-17 07:00:00+00:00,36.44
+2020-02-17 08:00:00+00:00,33.57
+2020-02-17 09:00:00+00:00,29.8
+2020-02-17 10:00:00+00:00,29.8
+2020-02-17 11:00:00+00:00,29.76
+2020-02-17 12:00:00+00:00,27.35
+2020-02-17 13:00:00+00:00,27.69
+2020-02-17 14:00:00+00:00,32.38
+2020-02-17 15:00:00+00:00,34.01
+2020-02-17 16:00:00+00:00,36.7
+2020-02-17 17:00:00+00:00,36.79
+2020-02-17 18:00:00+00:00,36.95
+2020-02-17 19:00:00+00:00,32.27
+2020-02-17 20:00:00+00:00,24.86
+2020-02-17 21:00:00+00:00,18.44
+2020-02-17 22:00:00+00:00,9.78
+2020-02-17 23:00:00+00:00,20.64
+2020-02-18 00:00:00+00:00,13.11
+2020-02-18 01:00:00+00:00,9.0
+2020-02-18 02:00:00+00:00,8.58
+2020-02-18 03:00:00+00:00,8.94
+2020-02-18 04:00:00+00:00,15.44
+2020-02-18 05:00:00+00:00,26.14
+2020-02-18 06:00:00+00:00,35.93
+2020-02-18 07:00:00+00:00,34.55
+2020-02-18 08:00:00+00:00,26.62
+2020-02-18 09:00:00+00:00,11.73
+2020-02-18 10:00:00+00:00,10.91
+2020-02-18 11:00:00+00:00,10.46
+2020-02-18 12:00:00+00:00,10.47
+2020-02-18 13:00:00+00:00,11.34
+2020-02-18 14:00:00+00:00,24.81
+2020-02-18 15:00:00+00:00,29.14
+2020-02-18 16:00:00+00:00,34.96
+2020-02-18 17:00:00+00:00,38.88
+2020-02-18 18:00:00+00:00,38.51
+2020-02-18 19:00:00+00:00,32.4
+2020-02-18 20:00:00+00:00,25.82
+2020-02-18 21:00:00+00:00,25.21
+2020-02-18 22:00:00+00:00,21.22
+2020-02-18 23:00:00+00:00,23.0
+2020-02-19 00:00:00+00:00,22.6
+2020-02-19 01:00:00+00:00,20.18
+2020-02-19 02:00:00+00:00,19.48
+2020-02-19 03:00:00+00:00,22.08
+2020-02-19 04:00:00+00:00,25.52
+2020-02-19 05:00:00+00:00,29.62
+2020-02-19 06:00:00+00:00,36.53
+2020-02-19 07:00:00+00:00,38.98
+2020-02-19 08:00:00+00:00,38.99
+2020-02-19 09:00:00+00:00,37.0
+2020-02-19 10:00:00+00:00,34.0
+2020-02-19 11:00:00+00:00,27.69
+2020-02-19 12:00:00+00:00,25.68
+2020-02-19 13:00:00+00:00,25.09
+2020-02-19 14:00:00+00:00,26.85
+2020-02-19 15:00:00+00:00,32.75
+2020-02-19 16:00:00+00:00,36.93
+2020-02-19 17:00:00+00:00,44.65
+2020-02-19 18:00:00+00:00,43.38
+2020-02-19 19:00:00+00:00,36.94
+2020-02-19 20:00:00+00:00,33.91
+2020-02-19 21:00:00+00:00,32.1
+2020-02-19 22:00:00+00:00,27.91
+2020-02-19 23:00:00+00:00,26.45
+2020-02-20 00:00:00+00:00,25.01
+2020-02-20 01:00:00+00:00,24.56
+2020-02-20 02:00:00+00:00,24.1
+2020-02-20 03:00:00+00:00,24.2
+2020-02-20 04:00:00+00:00,24.95
+2020-02-20 05:00:00+00:00,34.65
+2020-02-20 06:00:00+00:00,37.79
+2020-02-20 07:00:00+00:00,40.21
+2020-02-20 08:00:00+00:00,36.97
+2020-02-20 09:00:00+00:00,34.41
+2020-02-20 10:00:00+00:00,34.49
+2020-02-20 11:00:00+00:00,32.58
+2020-02-20 12:00:00+00:00,30.11
+2020-02-20 13:00:00+00:00,28.3
+2020-02-20 14:00:00+00:00,25.95
+2020-02-20 15:00:00+00:00,28.22
+2020-02-20 16:00:00+00:00,31.11
+2020-02-20 17:00:00+00:00,34.98
+2020-02-20 18:00:00+00:00,33.33
+2020-02-20 19:00:00+00:00,25.77
+2020-02-20 20:00:00+00:00,23.31
+2020-02-20 21:00:00+00:00,18.77
+2020-02-20 22:00:00+00:00,8.03
+2020-02-20 23:00:00+00:00,8.67
+2020-02-21 00:00:00+00:00,7.6
+2020-02-21 01:00:00+00:00,7.37
+2020-02-21 02:00:00+00:00,7.94
+2020-02-21 03:00:00+00:00,10.78
+2020-02-21 04:00:00+00:00,24.0
+2020-02-21 05:00:00+00:00,29.88
+2020-02-21 06:00:00+00:00,38.08
+2020-02-21 07:00:00+00:00,39.13
+2020-02-21 08:00:00+00:00,33.1
+2020-02-21 09:00:00+00:00,28.6
+2020-02-21 10:00:00+00:00,27.07
+2020-02-21 11:00:00+00:00,24.87
+2020-02-21 12:00:00+00:00,23.06
+2020-02-21 13:00:00+00:00,24.81
+2020-02-21 14:00:00+00:00,25.64
+2020-02-21 15:00:00+00:00,28.68
+2020-02-21 16:00:00+00:00,32.92
+2020-02-21 17:00:00+00:00,36.76
+2020-02-21 18:00:00+00:00,37.71
+2020-02-21 19:00:00+00:00,29.64
+2020-02-21 20:00:00+00:00,25.91
+2020-02-21 21:00:00+00:00,24.57
+2020-02-21 22:00:00+00:00,7.08
+2020-02-21 23:00:00+00:00,8.02
+2020-02-22 00:00:00+00:00,0.12
+2020-02-22 01:00:00+00:00,0.1
+2020-02-22 02:00:00+00:00,0.0
+2020-02-22 03:00:00+00:00,-2.99
+2020-02-22 04:00:00+00:00,-2.46
+2020-02-22 05:00:00+00:00,-7.99
+2020-02-22 06:00:00+00:00,-0.94
+2020-02-22 07:00:00+00:00,-0.02
+2020-02-22 08:00:00+00:00,-0.57
+2020-02-22 09:00:00+00:00,-4.95
+2020-02-22 10:00:00+00:00,-9.83
+2020-02-22 11:00:00+00:00,-5.1
+2020-02-22 12:00:00+00:00,-10.93
+2020-02-22 13:00:00+00:00,-9.94
+2020-02-22 14:00:00+00:00,-4.01
+2020-02-22 15:00:00+00:00,0.52
+2020-02-22 16:00:00+00:00,0.98
+2020-02-22 17:00:00+00:00,8.76
+2020-02-22 18:00:00+00:00,5.01
+2020-02-22 19:00:00+00:00,0.06
+2020-02-22 20:00:00+00:00,-0.09
+2020-02-22 21:00:00+00:00,0.04
+2020-02-22 22:00:00+00:00,0.0
+2020-02-22 23:00:00+00:00,-4.87
+2020-02-23 00:00:00+00:00,-2.99
+2020-02-23 01:00:00+00:00,-2.62
+2020-02-23 02:00:00+00:00,-4.89
+2020-02-23 03:00:00+00:00,-3.76
+2020-02-23 04:00:00+00:00,-0.07
+2020-02-23 05:00:00+00:00,-1.57
+2020-02-23 06:00:00+00:00,-2.44
+2020-02-23 07:00:00+00:00,0.87
+2020-02-23 08:00:00+00:00,14.14
+2020-02-23 09:00:00+00:00,17.1
+2020-02-23 10:00:00+00:00,23.57
+2020-02-23 11:00:00+00:00,22.76
+2020-02-23 12:00:00+00:00,15.03
+2020-02-23 13:00:00+00:00,9.05
+2020-02-23 14:00:00+00:00,8.71
+2020-02-23 15:00:00+00:00,8.51
+2020-02-23 16:00:00+00:00,10.25
+2020-02-23 17:00:00+00:00,15.77
+2020-02-23 18:00:00+00:00,10.25
+2020-02-23 19:00:00+00:00,8.6
+2020-02-23 20:00:00+00:00,8.34
+2020-02-23 21:00:00+00:00,8.94
+2020-02-23 22:00:00+00:00,8.18
+2020-02-23 23:00:00+00:00,-0.08
+2020-02-24 00:00:00+00:00,0.09
+2020-02-24 01:00:00+00:00,1.28
+2020-02-24 02:00:00+00:00,5.38
+2020-02-24 03:00:00+00:00,18.44
+2020-02-24 04:00:00+00:00,26.61
+2020-02-24 05:00:00+00:00,35.91
+2020-02-24 06:00:00+00:00,43.0
+2020-02-24 07:00:00+00:00,47.96
+2020-02-24 08:00:00+00:00,46.42
+2020-02-24 09:00:00+00:00,45.27
+2020-02-24 10:00:00+00:00,45.1
+2020-02-24 11:00:00+00:00,42.28
+2020-02-24 12:00:00+00:00,40.2
+2020-02-24 13:00:00+00:00,38.41
+2020-02-24 14:00:00+00:00,35.98
+2020-02-24 15:00:00+00:00,32.07
+2020-02-24 16:00:00+00:00,31.0
+2020-02-24 17:00:00+00:00,36.1
+2020-02-24 18:00:00+00:00,35.08
+2020-02-24 19:00:00+00:00,28.62
+2020-02-24 20:00:00+00:00,21.68
+2020-02-24 21:00:00+00:00,16.38
+2020-02-24 22:00:00+00:00,10.48
+2020-02-24 23:00:00+00:00,9.92
+2020-02-25 00:00:00+00:00,8.22
+2020-02-25 01:00:00+00:00,7.09
+2020-02-25 02:00:00+00:00,7.03
+2020-02-25 03:00:00+00:00,9.52
+2020-02-25 04:00:00+00:00,11.62
+2020-02-25 05:00:00+00:00,25.84
+2020-02-25 06:00:00+00:00,31.66
+2020-02-25 07:00:00+00:00,32.69
+2020-02-25 08:00:00+00:00,30.69
+2020-02-25 09:00:00+00:00,26.68
+2020-02-25 10:00:00+00:00,27.7
+2020-02-25 11:00:00+00:00,26.3
+2020-02-25 12:00:00+00:00,25.09
+2020-02-25 13:00:00+00:00,23.44
+2020-02-25 14:00:00+00:00,23.56
+2020-02-25 15:00:00+00:00,25.8
+2020-02-25 16:00:00+00:00,28.46
+2020-02-25 17:00:00+00:00,35.97
+2020-02-25 18:00:00+00:00,39.49
+2020-02-25 19:00:00+00:00,35.21
+2020-02-25 20:00:00+00:00,30.1
+2020-02-25 21:00:00+00:00,29.9
+2020-02-25 22:00:00+00:00,26.46
+2020-02-25 23:00:00+00:00,25.56
+2020-02-26 00:00:00+00:00,25.2
+2020-02-26 01:00:00+00:00,24.35
+2020-02-26 02:00:00+00:00,23.53
+2020-02-26 03:00:00+00:00,24.08
+2020-02-26 04:00:00+00:00,25.01
+2020-02-26 05:00:00+00:00,31.24
+2020-02-26 06:00:00+00:00,36.34
+2020-02-26 07:00:00+00:00,37.64
+2020-02-26 08:00:00+00:00,37.01
+2020-02-26 09:00:00+00:00,34.02
+2020-02-26 10:00:00+00:00,33.13
+2020-02-26 11:00:00+00:00,32.1
+2020-02-26 12:00:00+00:00,30.45
+2020-02-26 13:00:00+00:00,28.14
+2020-02-26 14:00:00+00:00,30.17
+2020-02-26 15:00:00+00:00,32.97
+2020-02-26 16:00:00+00:00,37.72
+2020-02-26 17:00:00+00:00,38.46
+2020-02-26 18:00:00+00:00,42.17
+2020-02-26 19:00:00+00:00,36.71
+2020-02-26 20:00:00+00:00,33.83
+2020-02-26 21:00:00+00:00,32.08
+2020-02-26 22:00:00+00:00,28.2
+2020-02-26 23:00:00+00:00,31.57
+2020-02-27 00:00:00+00:00,28.54
+2020-02-27 01:00:00+00:00,27.04
+2020-02-27 02:00:00+00:00,25.17
+2020-02-27 03:00:00+00:00,25.45
+2020-02-27 04:00:00+00:00,28.81
+2020-02-27 05:00:00+00:00,36.8
+2020-02-27 06:00:00+00:00,42.28
+2020-02-27 07:00:00+00:00,44.42
+2020-02-27 08:00:00+00:00,42.41
+2020-02-27 09:00:00+00:00,40.15
+2020-02-27 10:00:00+00:00,40.05
+2020-02-27 11:00:00+00:00,38.82
+2020-02-27 12:00:00+00:00,39.81
+2020-02-27 13:00:00+00:00,43.71
+2020-02-27 14:00:00+00:00,45.19
+2020-02-27 15:00:00+00:00,45.71
+2020-02-27 16:00:00+00:00,51.52
+2020-02-27 17:00:00+00:00,59.98
+2020-02-27 18:00:00+00:00,48.06
+2020-02-27 19:00:00+00:00,39.13
+2020-02-27 20:00:00+00:00,35.68
+2020-02-27 21:00:00+00:00,33.77
+2020-02-27 22:00:00+00:00,28.54
+2020-02-27 23:00:00+00:00,29.54
+2020-02-28 00:00:00+00:00,26.7
+2020-02-28 01:00:00+00:00,25.34
+2020-02-28 02:00:00+00:00,24.87
+2020-02-28 03:00:00+00:00,24.87
+2020-02-28 04:00:00+00:00,27.3
+2020-02-28 05:00:00+00:00,34.97
+2020-02-28 06:00:00+00:00,40.74
+2020-02-28 07:00:00+00:00,43.88
+2020-02-28 08:00:00+00:00,40.12
+2020-02-28 09:00:00+00:00,37.81
+2020-02-28 10:00:00+00:00,32.5
+2020-02-28 11:00:00+00:00,26.55
+2020-02-28 12:00:00+00:00,26.0
+2020-02-28 13:00:00+00:00,26.12
+2020-02-28 14:00:00+00:00,27.1
+2020-02-28 15:00:00+00:00,34.01
+2020-02-28 16:00:00+00:00,37.49
+2020-02-28 17:00:00+00:00,38.95
+2020-02-28 18:00:00+00:00,35.34
+2020-02-28 19:00:00+00:00,27.77
+2020-02-28 20:00:00+00:00,27.06
+2020-02-28 21:00:00+00:00,26.14
+2020-02-28 22:00:00+00:00,23.79
+2020-02-28 23:00:00+00:00,0.4
+2020-02-29 00:00:00+00:00,3.11
+2020-02-29 01:00:00+00:00,9.42
+2020-02-29 02:00:00+00:00,9.49
+2020-02-29 03:00:00+00:00,9.39
+2020-02-29 04:00:00+00:00,8.67
+2020-02-29 05:00:00+00:00,10.18
+2020-02-29 06:00:00+00:00,11.56
+2020-02-29 07:00:00+00:00,12.99
+2020-02-29 08:00:00+00:00,14.01
+2020-02-29 09:00:00+00:00,12.36
+2020-02-29 10:00:00+00:00,9.97
+2020-02-29 11:00:00+00:00,6.71
+2020-02-29 12:00:00+00:00,4.22
+2020-02-29 13:00:00+00:00,4.21
+2020-02-29 14:00:00+00:00,7.63
+2020-02-29 15:00:00+00:00,5.22
+2020-02-29 16:00:00+00:00,12.25
+2020-02-29 17:00:00+00:00,13.92
+2020-02-29 18:00:00+00:00,12.78
+2020-02-29 19:00:00+00:00,8.06
+2020-02-29 20:00:00+00:00,7.38
+2020-02-29 21:00:00+00:00,10.41
+2020-02-29 22:00:00+00:00,9.51
+2020-02-29 23:00:00+00:00,-4.92
+2020-03-01 00:00:00+00:00,-3.88
+2020-03-01 01:00:00+00:00,-6.98
+2020-03-01 02:00:00+00:00,-3.88
+2020-03-01 03:00:00+00:00,-1.02
+2020-03-01 04:00:00+00:00,-1.03
+2020-03-01 05:00:00+00:00,-5.3
+2020-03-01 06:00:00+00:00,-3.89
+2020-03-01 07:00:00+00:00,-0.05
+2020-03-01 08:00:00+00:00,-0.23
+2020-03-01 09:00:00+00:00,-4.03
+2020-03-01 10:00:00+00:00,-2.16
+2020-03-01 11:00:00+00:00,-6.97
+2020-03-01 12:00:00+00:00,-7.85
+2020-03-01 13:00:00+00:00,-5.06
+2020-03-01 14:00:00+00:00,0.03
+2020-03-01 15:00:00+00:00,15.11
+2020-03-01 16:00:00+00:00,33.07
+2020-03-01 17:00:00+00:00,34.7
+2020-03-01 18:00:00+00:00,36.12
+2020-03-01 19:00:00+00:00,31.49
+2020-03-01 20:00:00+00:00,26.1
+2020-03-01 21:00:00+00:00,27.76
+2020-03-01 22:00:00+00:00,24.24
+2020-03-01 23:00:00+00:00,24.31
+2020-03-02 00:00:00+00:00,23.3
+2020-03-02 01:00:00+00:00,21.71
+2020-03-02 02:00:00+00:00,19.2
+2020-03-02 03:00:00+00:00,19.15
+2020-03-02 04:00:00+00:00,23.53
+2020-03-02 05:00:00+00:00,30.91
+2020-03-02 06:00:00+00:00,37.0
+2020-03-02 07:00:00+00:00,39.92
+2020-03-02 08:00:00+00:00,36.94
+2020-03-02 09:00:00+00:00,36.71
+2020-03-02 10:00:00+00:00,37.03
+2020-03-02 11:00:00+00:00,35.13
+2020-03-02 12:00:00+00:00,35.35
+2020-03-02 13:00:00+00:00,34.74
+2020-03-02 14:00:00+00:00,36.79
+2020-03-02 15:00:00+00:00,38.93
+2020-03-02 16:00:00+00:00,41.09
+2020-03-02 17:00:00+00:00,49.5
+2020-03-02 18:00:00+00:00,43.92
+2020-03-02 19:00:00+00:00,37.75
+2020-03-02 20:00:00+00:00,33.54
+2020-03-02 21:00:00+00:00,30.88
+2020-03-02 22:00:00+00:00,28.97
+2020-03-02 23:00:00+00:00,26.04
+2020-03-03 00:00:00+00:00,25.04
+2020-03-03 01:00:00+00:00,24.53
+2020-03-03 02:00:00+00:00,24.1
+2020-03-03 03:00:00+00:00,24.45
+2020-03-03 04:00:00+00:00,28.5
+2020-03-03 05:00:00+00:00,35.68
+2020-03-03 06:00:00+00:00,42.3
+2020-03-03 07:00:00+00:00,45.6
+2020-03-03 08:00:00+00:00,41.68
+2020-03-03 09:00:00+00:00,37.97
+2020-03-03 10:00:00+00:00,34.83
+2020-03-03 11:00:00+00:00,31.82
+2020-03-03 12:00:00+00:00,33.96
+2020-03-03 13:00:00+00:00,35.93
+2020-03-03 14:00:00+00:00,37.66
+2020-03-03 15:00:00+00:00,39.84
+2020-03-03 16:00:00+00:00,41.73
+2020-03-03 17:00:00+00:00,55.98
+2020-03-03 18:00:00+00:00,56.9
+2020-03-03 19:00:00+00:00,40.93
+2020-03-03 20:00:00+00:00,38.19
+2020-03-03 21:00:00+00:00,35.03
+2020-03-03 22:00:00+00:00,31.29
+2020-03-03 23:00:00+00:00,30.1
+2020-03-04 00:00:00+00:00,28.1
+2020-03-04 01:00:00+00:00,27.08
+2020-03-04 02:00:00+00:00,26.8
+2020-03-04 03:00:00+00:00,26.8
+2020-03-04 04:00:00+00:00,30.05
+2020-03-04 05:00:00+00:00,36.51
+2020-03-04 06:00:00+00:00,47.2
+2020-03-04 07:00:00+00:00,54.75
+2020-03-04 08:00:00+00:00,50.32
+2020-03-04 09:00:00+00:00,44.23
+2020-03-04 10:00:00+00:00,41.09
+2020-03-04 11:00:00+00:00,37.9
+2020-03-04 12:00:00+00:00,35.97
+2020-03-04 13:00:00+00:00,35.0
+2020-03-04 14:00:00+00:00,35.88
+2020-03-04 15:00:00+00:00,39.5
+2020-03-04 16:00:00+00:00,48.49
+2020-03-04 17:00:00+00:00,64.7
+2020-03-04 18:00:00+00:00,63.34
+2020-03-04 19:00:00+00:00,43.58
+2020-03-04 20:00:00+00:00,37.53
+2020-03-04 21:00:00+00:00,33.92
+2020-03-04 22:00:00+00:00,31.82
+2020-03-04 23:00:00+00:00,30.24
+2020-03-05 00:00:00+00:00,29.08
+2020-03-05 01:00:00+00:00,28.6
+2020-03-05 02:00:00+00:00,29.01
+2020-03-05 03:00:00+00:00,30.1
+2020-03-05 04:00:00+00:00,31.55
+2020-03-05 05:00:00+00:00,37.91
+2020-03-05 06:00:00+00:00,45.61
+2020-03-05 07:00:00+00:00,54.64
+2020-03-05 08:00:00+00:00,49.78
+2020-03-05 09:00:00+00:00,42.09
+2020-03-05 10:00:00+00:00,40.99
+2020-03-05 11:00:00+00:00,41.97
+2020-03-05 12:00:00+00:00,40.51
+2020-03-05 13:00:00+00:00,37.94
+2020-03-05 14:00:00+00:00,36.75
+2020-03-05 15:00:00+00:00,37.03
+2020-03-05 16:00:00+00:00,38.91
+2020-03-05 17:00:00+00:00,36.9
+2020-03-05 18:00:00+00:00,35.82
+2020-03-05 19:00:00+00:00,30.24
+2020-03-05 20:00:00+00:00,27.85
+2020-03-05 21:00:00+00:00,26.9
+2020-03-05 22:00:00+00:00,25.3
+2020-03-05 23:00:00+00:00,24.55
+2020-03-06 00:00:00+00:00,22.96
+2020-03-06 01:00:00+00:00,21.0
+2020-03-06 02:00:00+00:00,19.99
+2020-03-06 03:00:00+00:00,20.22
+2020-03-06 04:00:00+00:00,24.1
+2020-03-06 05:00:00+00:00,28.8
+2020-03-06 06:00:00+00:00,33.41
+2020-03-06 07:00:00+00:00,35.9
+2020-03-06 08:00:00+00:00,35.1
+2020-03-06 09:00:00+00:00,34.68
+2020-03-06 10:00:00+00:00,36.03
+2020-03-06 11:00:00+00:00,35.0
+2020-03-06 12:00:00+00:00,32.64
+2020-03-06 13:00:00+00:00,31.67
+2020-03-06 14:00:00+00:00,29.06
+2020-03-06 15:00:00+00:00,29.8
+2020-03-06 16:00:00+00:00,35.0
+2020-03-06 17:00:00+00:00,37.3
+2020-03-06 18:00:00+00:00,38.04
+2020-03-06 19:00:00+00:00,35.46
+2020-03-06 20:00:00+00:00,31.71
+2020-03-06 21:00:00+00:00,30.5
+2020-03-06 22:00:00+00:00,28.54
+2020-03-06 23:00:00+00:00,31.01
+2020-03-07 00:00:00+00:00,25.5
+2020-03-07 01:00:00+00:00,24.51
+2020-03-07 02:00:00+00:00,24.03
+2020-03-07 03:00:00+00:00,24.47
+2020-03-07 04:00:00+00:00,24.41
+2020-03-07 05:00:00+00:00,26.25
+2020-03-07 06:00:00+00:00,30.4
+2020-03-07 07:00:00+00:00,33.58
+2020-03-07 08:00:00+00:00,35.0
+2020-03-07 09:00:00+00:00,30.4
+2020-03-07 10:00:00+00:00,28.1
+2020-03-07 11:00:00+00:00,26.08
+2020-03-07 12:00:00+00:00,25.06
+2020-03-07 13:00:00+00:00,24.94
+2020-03-07 14:00:00+00:00,25.0
+2020-03-07 15:00:00+00:00,29.54
+2020-03-07 16:00:00+00:00,35.79
+2020-03-07 17:00:00+00:00,38.8
+2020-03-07 18:00:00+00:00,39.95
+2020-03-07 19:00:00+00:00,35.0
+2020-03-07 20:00:00+00:00,27.17
+2020-03-07 21:00:00+00:00,28.24
+2020-03-07 22:00:00+00:00,24.9
+2020-03-07 23:00:00+00:00,20.8
+2020-03-08 00:00:00+00:00,16.82
+2020-03-08 01:00:00+00:00,12.22
+2020-03-08 02:00:00+00:00,9.24
+2020-03-08 03:00:00+00:00,8.74
+2020-03-08 04:00:00+00:00,8.93
+2020-03-08 05:00:00+00:00,8.67
+2020-03-08 06:00:00+00:00,9.78
+2020-03-08 07:00:00+00:00,9.66
+2020-03-08 08:00:00+00:00,9.38
+2020-03-08 09:00:00+00:00,9.73
+2020-03-08 10:00:00+00:00,9.4
+2020-03-08 11:00:00+00:00,8.93
+2020-03-08 12:00:00+00:00,8.43
+2020-03-08 13:00:00+00:00,8.77
+2020-03-08 14:00:00+00:00,11.01
+2020-03-08 15:00:00+00:00,19.19
+2020-03-08 16:00:00+00:00,25.71
+2020-03-08 17:00:00+00:00,31.97
+2020-03-08 18:00:00+00:00,34.86
+2020-03-08 19:00:00+00:00,34.02
+2020-03-08 20:00:00+00:00,31.9
+2020-03-08 21:00:00+00:00,31.99
+2020-03-08 22:00:00+00:00,30.41
+2020-03-08 23:00:00+00:00,25.02
+2020-03-09 00:00:00+00:00,25.0
+2020-03-09 01:00:00+00:00,25.09
+2020-03-09 02:00:00+00:00,24.77
+2020-03-09 03:00:00+00:00,24.47
+2020-03-09 04:00:00+00:00,25.3
+2020-03-09 05:00:00+00:00,37.1
+2020-03-09 06:00:00+00:00,46.99
+2020-03-09 07:00:00+00:00,50.27
+2020-03-09 08:00:00+00:00,45.65
+2020-03-09 09:00:00+00:00,40.44
+2020-03-09 10:00:00+00:00,40.35
+2020-03-09 11:00:00+00:00,36.88
+2020-03-09 12:00:00+00:00,35.49
+2020-03-09 13:00:00+00:00,33.75
+2020-03-09 14:00:00+00:00,36.75
+2020-03-09 15:00:00+00:00,39.3
+2020-03-09 16:00:00+00:00,46.35
+2020-03-09 17:00:00+00:00,54.57
+2020-03-09 18:00:00+00:00,58.98
+2020-03-09 19:00:00+00:00,40.5
+2020-03-09 20:00:00+00:00,35.98
+2020-03-09 21:00:00+00:00,34.97
+2020-03-09 22:00:00+00:00,26.75
+2020-03-09 23:00:00+00:00,24.06
+2020-03-10 00:00:00+00:00,23.7
+2020-03-10 01:00:00+00:00,21.77
+2020-03-10 02:00:00+00:00,15.91
+2020-03-10 03:00:00+00:00,13.06
+2020-03-10 04:00:00+00:00,15.8
+2020-03-10 05:00:00+00:00,24.23
+2020-03-10 06:00:00+00:00,29.0
+2020-03-10 07:00:00+00:00,30.19
+2020-03-10 08:00:00+00:00,31.08
+2020-03-10 09:00:00+00:00,30.1
+2020-03-10 10:00:00+00:00,31.77
+2020-03-10 11:00:00+00:00,30.55
+2020-03-10 12:00:00+00:00,30.0
+2020-03-10 13:00:00+00:00,29.69
+2020-03-10 14:00:00+00:00,24.84
+2020-03-10 15:00:00+00:00,22.64
+2020-03-10 16:00:00+00:00,24.27
+2020-03-10 17:00:00+00:00,28.17
+2020-03-10 18:00:00+00:00,27.37
+2020-03-10 19:00:00+00:00,24.04
+2020-03-10 20:00:00+00:00,11.79
+2020-03-10 21:00:00+00:00,9.03
+2020-03-10 22:00:00+00:00,4.93
+2020-03-10 23:00:00+00:00,-0.05
+2020-03-11 00:00:00+00:00,0.07
+2020-03-11 01:00:00+00:00,0.1
+2020-03-11 02:00:00+00:00,0.13
+2020-03-11 03:00:00+00:00,5.58
+2020-03-11 04:00:00+00:00,21.13
+2020-03-11 05:00:00+00:00,26.87
+2020-03-11 06:00:00+00:00,33.94
+2020-03-11 07:00:00+00:00,37.17
+2020-03-11 08:00:00+00:00,34.27
+2020-03-11 09:00:00+00:00,33.07
+2020-03-11 10:00:00+00:00,29.2
+2020-03-11 11:00:00+00:00,25.97
+2020-03-11 12:00:00+00:00,24.06
+2020-03-11 13:00:00+00:00,23.73
+2020-03-11 14:00:00+00:00,24.9
+2020-03-11 15:00:00+00:00,26.66
+2020-03-11 16:00:00+00:00,33.8
+2020-03-11 17:00:00+00:00,37.0
+2020-03-11 18:00:00+00:00,37.99
+2020-03-11 19:00:00+00:00,28.1
+2020-03-11 20:00:00+00:00,24.39
+2020-03-11 21:00:00+00:00,23.84
+2020-03-11 22:00:00+00:00,12.58
+2020-03-11 23:00:00+00:00,7.37
+2020-03-12 00:00:00+00:00,1.79
+2020-03-12 01:00:00+00:00,0.06
+2020-03-12 02:00:00+00:00,0.01
+2020-03-12 03:00:00+00:00,-1.58
+2020-03-12 04:00:00+00:00,0.13
+2020-03-12 05:00:00+00:00,10.64
+2020-03-12 06:00:00+00:00,19.98
+2020-03-12 07:00:00+00:00,18.05
+2020-03-12 08:00:00+00:00,9.18
+2020-03-12 09:00:00+00:00,-0.01
+2020-03-12 10:00:00+00:00,-0.05
+2020-03-12 11:00:00+00:00,0.03
+2020-03-12 12:00:00+00:00,0.56
+2020-03-12 13:00:00+00:00,0.08
+2020-03-12 14:00:00+00:00,12.73
+2020-03-12 15:00:00+00:00,23.6
+2020-03-12 16:00:00+00:00,27.45
+2020-03-12 17:00:00+00:00,37.0
+2020-03-12 18:00:00+00:00,39.63
+2020-03-12 19:00:00+00:00,31.76
+2020-03-12 20:00:00+00:00,24.5
+2020-03-12 21:00:00+00:00,23.26
+2020-03-12 22:00:00+00:00,7.5
+2020-03-12 23:00:00+00:00,7.59
+2020-03-13 00:00:00+00:00,6.99
+2020-03-13 01:00:00+00:00,2.48
+2020-03-13 02:00:00+00:00,2.95
+2020-03-13 03:00:00+00:00,2.58
+2020-03-13 04:00:00+00:00,7.96
+2020-03-13 05:00:00+00:00,21.83
+2020-03-13 06:00:00+00:00,24.94
+2020-03-13 07:00:00+00:00,13.99
+2020-03-13 08:00:00+00:00,4.02
+2020-03-13 09:00:00+00:00,0.09
+2020-03-13 10:00:00+00:00,10.69
+2020-03-13 11:00:00+00:00,4.08
+2020-03-13 12:00:00+00:00,0.12
+2020-03-13 13:00:00+00:00,0.01
+2020-03-13 14:00:00+00:00,4.68
+2020-03-13 15:00:00+00:00,21.37
+2020-03-13 16:00:00+00:00,32.65
+2020-03-13 17:00:00+00:00,37.7
+2020-03-13 18:00:00+00:00,42.5
+2020-03-13 19:00:00+00:00,38.41
+2020-03-13 20:00:00+00:00,36.93
+2020-03-13 21:00:00+00:00,36.99
+2020-03-13 22:00:00+00:00,35.35
+2020-03-13 23:00:00+00:00,34.29
+2020-03-14 00:00:00+00:00,32.04
+2020-03-14 01:00:00+00:00,31.43
+2020-03-14 02:00:00+00:00,29.05
+2020-03-14 03:00:00+00:00,29.27
+2020-03-14 04:00:00+00:00,31.15
+2020-03-14 05:00:00+00:00,34.61
+2020-03-14 06:00:00+00:00,34.9
+2020-03-14 07:00:00+00:00,34.83
+2020-03-14 08:00:00+00:00,34.94
+2020-03-14 09:00:00+00:00,29.13
+2020-03-14 10:00:00+00:00,26.96
+2020-03-14 11:00:00+00:00,26.01
+2020-03-14 12:00:00+00:00,23.81
+2020-03-14 13:00:00+00:00,22.62
+2020-03-14 14:00:00+00:00,24.87
+2020-03-14 15:00:00+00:00,25.8
+2020-03-14 16:00:00+00:00,34.82
+2020-03-14 17:00:00+00:00,37.17
+2020-03-14 18:00:00+00:00,38.53
+2020-03-14 19:00:00+00:00,32.79
+2020-03-14 20:00:00+00:00,27.42
+2020-03-14 21:00:00+00:00,26.02
+2020-03-14 22:00:00+00:00,23.95
+2020-03-14 23:00:00+00:00,14.23
+2020-03-15 00:00:00+00:00,7.24
+2020-03-15 01:00:00+00:00,6.69
+2020-03-15 02:00:00+00:00,5.98
+2020-03-15 03:00:00+00:00,5.97
+2020-03-15 04:00:00+00:00,4.34
+2020-03-15 05:00:00+00:00,4.34
+2020-03-15 06:00:00+00:00,0.05
+2020-03-15 07:00:00+00:00,0.08
+2020-03-15 08:00:00+00:00,-0.01
+2020-03-15 09:00:00+00:00,-2.02
+2020-03-15 10:00:00+00:00,-8.79
+2020-03-15 11:00:00+00:00,-33.67
+2020-03-15 12:00:00+00:00,-33.8
+2020-03-15 13:00:00+00:00,-29.05
+2020-03-15 14:00:00+00:00,-4.96
+2020-03-15 15:00:00+00:00,0.07
+2020-03-15 16:00:00+00:00,13.13
+2020-03-15 17:00:00+00:00,26.0
+2020-03-15 18:00:00+00:00,29.96
+2020-03-15 19:00:00+00:00,26.44
+2020-03-15 20:00:00+00:00,25.23
+2020-03-15 21:00:00+00:00,30.18
+2020-03-15 22:00:00+00:00,23.93
+2020-03-15 23:00:00+00:00,20.01
+2020-03-16 00:00:00+00:00,20.13
+2020-03-16 01:00:00+00:00,20.04
+2020-03-16 02:00:00+00:00,20.0
+2020-03-16 03:00:00+00:00,19.92
+2020-03-16 04:00:00+00:00,22.4
+2020-03-16 05:00:00+00:00,33.85
+2020-03-16 06:00:00+00:00,38.34
+2020-03-16 07:00:00+00:00,36.92
+2020-03-16 08:00:00+00:00,32.13
+2020-03-16 09:00:00+00:00,28.0
+2020-03-16 10:00:00+00:00,25.88
+2020-03-16 11:00:00+00:00,24.83
+2020-03-16 12:00:00+00:00,25.0
+2020-03-16 13:00:00+00:00,25.23
+2020-03-16 14:00:00+00:00,27.1
+2020-03-16 15:00:00+00:00,30.77
+2020-03-16 16:00:00+00:00,37.25
+2020-03-16 17:00:00+00:00,54.93
+2020-03-16 18:00:00+00:00,61.96
+2020-03-16 19:00:00+00:00,43.1
+2020-03-16 20:00:00+00:00,35.99
+2020-03-16 21:00:00+00:00,34.56
+2020-03-16 22:00:00+00:00,30.24
+2020-03-16 23:00:00+00:00,25.54
+2020-03-17 00:00:00+00:00,23.49
+2020-03-17 01:00:00+00:00,23.06
+2020-03-17 02:00:00+00:00,22.71
+2020-03-17 03:00:00+00:00,23.0
+2020-03-17 04:00:00+00:00,23.87
+2020-03-17 05:00:00+00:00,30.48
+2020-03-17 06:00:00+00:00,35.17
+2020-03-17 07:00:00+00:00,34.39
+2020-03-17 08:00:00+00:00,31.37
+2020-03-17 09:00:00+00:00,28.89
+2020-03-17 10:00:00+00:00,24.02
+2020-03-17 11:00:00+00:00,25.55
+2020-03-17 12:00:00+00:00,23.9
+2020-03-17 13:00:00+00:00,24.61
+2020-03-17 14:00:00+00:00,24.02
+2020-03-17 15:00:00+00:00,26.09
+2020-03-17 16:00:00+00:00,30.04
+2020-03-17 17:00:00+00:00,35.93
+2020-03-17 18:00:00+00:00,38.23
+2020-03-17 19:00:00+00:00,35.21
+2020-03-17 20:00:00+00:00,31.0
+2020-03-17 21:00:00+00:00,29.85
+2020-03-17 22:00:00+00:00,25.97
+2020-03-17 23:00:00+00:00,22.02
+2020-03-18 00:00:00+00:00,21.73
+2020-03-18 01:00:00+00:00,20.76
+2020-03-18 02:00:00+00:00,20.77
+2020-03-18 03:00:00+00:00,20.73
+2020-03-18 04:00:00+00:00,21.06
+2020-03-18 05:00:00+00:00,24.69
+2020-03-18 06:00:00+00:00,30.59
+2020-03-18 07:00:00+00:00,29.79
+2020-03-18 08:00:00+00:00,22.99
+2020-03-18 09:00:00+00:00,20.4
+2020-03-18 10:00:00+00:00,20.64
+2020-03-18 11:00:00+00:00,20.34
+2020-03-18 12:00:00+00:00,20.74
+2020-03-18 13:00:00+00:00,21.8
+2020-03-18 14:00:00+00:00,24.76
+2020-03-18 15:00:00+00:00,28.62
+2020-03-18 16:00:00+00:00,33.0
+2020-03-18 17:00:00+00:00,37.56
+2020-03-18 18:00:00+00:00,41.07
+2020-03-18 19:00:00+00:00,35.4
+2020-03-18 20:00:00+00:00,33.7
+2020-03-18 21:00:00+00:00,31.83
+2020-03-18 22:00:00+00:00,29.06
+2020-03-18 23:00:00+00:00,26.67
+2020-03-19 00:00:00+00:00,24.0
+2020-03-19 01:00:00+00:00,22.99
+2020-03-19 02:00:00+00:00,22.16
+2020-03-19 03:00:00+00:00,22.26
+2020-03-19 04:00:00+00:00,26.0
+2020-03-19 05:00:00+00:00,30.25
+2020-03-19 06:00:00+00:00,33.98
+2020-03-19 07:00:00+00:00,32.06
+2020-03-19 08:00:00+00:00,28.75
+2020-03-19 09:00:00+00:00,25.04
+2020-03-19 10:00:00+00:00,24.93
+2020-03-19 11:00:00+00:00,22.83
+2020-03-19 12:00:00+00:00,22.99
+2020-03-19 13:00:00+00:00,24.92
+2020-03-19 14:00:00+00:00,27.9
+2020-03-19 15:00:00+00:00,30.57
+2020-03-19 16:00:00+00:00,33.73
+2020-03-19 17:00:00+00:00,40.2
+2020-03-19 18:00:00+00:00,44.42
+2020-03-19 19:00:00+00:00,34.48
+2020-03-19 20:00:00+00:00,31.65
+2020-03-19 21:00:00+00:00,28.7
+2020-03-19 22:00:00+00:00,27.1
+2020-03-19 23:00:00+00:00,25.18
+2020-03-20 00:00:00+00:00,20.0
+2020-03-20 01:00:00+00:00,20.87
+2020-03-20 02:00:00+00:00,20.72
+2020-03-20 03:00:00+00:00,25.0
+2020-03-20 04:00:00+00:00,26.45
+2020-03-20 05:00:00+00:00,31.9
+2020-03-20 06:00:00+00:00,35.0
+2020-03-20 07:00:00+00:00,33.88
+2020-03-20 08:00:00+00:00,28.08
+2020-03-20 09:00:00+00:00,25.99
+2020-03-20 10:00:00+00:00,25.36
+2020-03-20 11:00:00+00:00,22.85
+2020-03-20 12:00:00+00:00,21.59
+2020-03-20 13:00:00+00:00,20.38
+2020-03-20 14:00:00+00:00,22.72
+2020-03-20 15:00:00+00:00,25.03
+2020-03-20 16:00:00+00:00,27.72
+2020-03-20 17:00:00+00:00,29.58
+2020-03-20 18:00:00+00:00,28.92
+2020-03-20 19:00:00+00:00,25.06
+2020-03-20 20:00:00+00:00,20.05
+2020-03-20 21:00:00+00:00,21.02
+2020-03-20 22:00:00+00:00,19.9
+2020-03-20 23:00:00+00:00,18.23
+2020-03-21 00:00:00+00:00,13.97
+2020-03-21 01:00:00+00:00,11.16
+2020-03-21 02:00:00+00:00,9.43
+2020-03-21 03:00:00+00:00,8.94
+2020-03-21 04:00:00+00:00,9.5
+2020-03-21 05:00:00+00:00,7.74
+2020-03-21 06:00:00+00:00,10.8
+2020-03-21 07:00:00+00:00,15.05
+2020-03-21 08:00:00+00:00,8.64
+2020-03-21 09:00:00+00:00,7.51
+2020-03-21 10:00:00+00:00,7.18
+2020-03-21 11:00:00+00:00,7.13
+2020-03-21 12:00:00+00:00,6.17
+2020-03-21 13:00:00+00:00,0.39
+2020-03-21 14:00:00+00:00,5.7
+2020-03-21 15:00:00+00:00,8.3
+2020-03-21 16:00:00+00:00,15.01
+2020-03-21 17:00:00+00:00,20.0
+2020-03-21 18:00:00+00:00,20.12
+2020-03-21 19:00:00+00:00,15.34
+2020-03-21 20:00:00+00:00,9.29
+2020-03-21 21:00:00+00:00,11.29
+2020-03-21 22:00:00+00:00,10.79
+2020-03-21 23:00:00+00:00,7.51
+2020-03-22 00:00:00+00:00,7.51
+2020-03-22 01:00:00+00:00,7.24
+2020-03-22 02:00:00+00:00,6.25
+2020-03-22 03:00:00+00:00,6.09
+2020-03-22 04:00:00+00:00,6.24
+2020-03-22 05:00:00+00:00,6.06
+2020-03-22 06:00:00+00:00,5.68
+2020-03-22 07:00:00+00:00,2.94
+2020-03-22 08:00:00+00:00,-3.63
+2020-03-22 09:00:00+00:00,-20.8
+2020-03-22 10:00:00+00:00,-25.1
+2020-03-22 11:00:00+00:00,-38.48
+2020-03-22 12:00:00+00:00,-55.05
+2020-03-22 13:00:00+00:00,-36.63
+2020-03-22 14:00:00+00:00,-11.98
+2020-03-22 15:00:00+00:00,0.02
+2020-03-22 16:00:00+00:00,11.04
+2020-03-22 17:00:00+00:00,19.78
+2020-03-22 18:00:00+00:00,22.93
+2020-03-22 19:00:00+00:00,19.45
+2020-03-22 20:00:00+00:00,14.36
+2020-03-22 21:00:00+00:00,14.79
+2020-03-22 22:00:00+00:00,11.05
+2020-03-22 23:00:00+00:00,12.07
+2020-03-23 00:00:00+00:00,10.0
+2020-03-23 01:00:00+00:00,10.17
+2020-03-23 02:00:00+00:00,9.28
+2020-03-23 03:00:00+00:00,9.28
+2020-03-23 04:00:00+00:00,12.76
+2020-03-23 05:00:00+00:00,20.0
+2020-03-23 06:00:00+00:00,23.99
+2020-03-23 07:00:00+00:00,20.08
+2020-03-23 08:00:00+00:00,15.84
+2020-03-23 09:00:00+00:00,10.66
+2020-03-23 10:00:00+00:00,10.7
+2020-03-23 11:00:00+00:00,10.62
+2020-03-23 12:00:00+00:00,10.92
+2020-03-23 13:00:00+00:00,12.07
+2020-03-23 14:00:00+00:00,12.01
+2020-03-23 15:00:00+00:00,17.4
+2020-03-23 16:00:00+00:00,25.95
+2020-03-23 17:00:00+00:00,30.67
+2020-03-23 18:00:00+00:00,33.14
+2020-03-23 19:00:00+00:00,27.99
+2020-03-23 20:00:00+00:00,21.97
+2020-03-23 21:00:00+00:00,21.84
+2020-03-23 22:00:00+00:00,18.18
+2020-03-23 23:00:00+00:00,16.63
+2020-03-24 00:00:00+00:00,17.55
+2020-03-24 01:00:00+00:00,16.53
+2020-03-24 02:00:00+00:00,16.81
+2020-03-24 03:00:00+00:00,17.6
+2020-03-24 04:00:00+00:00,19.8
+2020-03-24 05:00:00+00:00,23.63
+2020-03-24 06:00:00+00:00,25.88
+2020-03-24 07:00:00+00:00,20.35
+2020-03-24 08:00:00+00:00,17.5
+2020-03-24 09:00:00+00:00,14.16
+2020-03-24 10:00:00+00:00,15.08
+2020-03-24 11:00:00+00:00,14.3
+2020-03-24 12:00:00+00:00,13.0
+2020-03-24 13:00:00+00:00,14.33
+2020-03-24 14:00:00+00:00,16.65
+2020-03-24 15:00:00+00:00,19.79
+2020-03-24 16:00:00+00:00,27.75
+2020-03-24 17:00:00+00:00,33.8
+2020-03-24 18:00:00+00:00,33.78
+2020-03-24 19:00:00+00:00,29.65
+2020-03-24 20:00:00+00:00,22.98
+2020-03-24 21:00:00+00:00,22.98
+2020-03-24 22:00:00+00:00,20.31
+2020-03-24 23:00:00+00:00,19.29
+2020-03-25 00:00:00+00:00,19.21
+2020-03-25 01:00:00+00:00,19.5
+2020-03-25 02:00:00+00:00,19.33
+2020-03-25 03:00:00+00:00,19.26
+2020-03-25 04:00:00+00:00,21.51
+2020-03-25 05:00:00+00:00,25.84
+2020-03-25 06:00:00+00:00,29.15
+2020-03-25 07:00:00+00:00,27.64
+2020-03-25 08:00:00+00:00,23.62
+2020-03-25 09:00:00+00:00,20.05
+2020-03-25 10:00:00+00:00,19.57
+2020-03-25 11:00:00+00:00,19.97
+2020-03-25 12:00:00+00:00,19.05
+2020-03-25 13:00:00+00:00,18.7
+2020-03-25 14:00:00+00:00,17.57
+2020-03-25 15:00:00+00:00,19.96
+2020-03-25 16:00:00+00:00,27.09
+2020-03-25 17:00:00+00:00,34.88
+2020-03-25 18:00:00+00:00,34.48
+2020-03-25 19:00:00+00:00,28.09
+2020-03-25 20:00:00+00:00,24.51
+2020-03-25 21:00:00+00:00,24.02
+2020-03-25 22:00:00+00:00,21.18
+2020-03-25 23:00:00+00:00,19.68
+2020-03-26 00:00:00+00:00,18.39
+2020-03-26 01:00:00+00:00,19.1
+2020-03-26 02:00:00+00:00,18.39
+2020-03-26 03:00:00+00:00,18.32
+2020-03-26 04:00:00+00:00,19.8
+2020-03-26 05:00:00+00:00,22.2
+2020-03-26 06:00:00+00:00,25.53
+2020-03-26 07:00:00+00:00,25.0
+2020-03-26 08:00:00+00:00,21.32
+2020-03-26 09:00:00+00:00,19.11
+2020-03-26 10:00:00+00:00,18.16
+2020-03-26 11:00:00+00:00,17.67
+2020-03-26 12:00:00+00:00,15.32
+2020-03-26 13:00:00+00:00,16.82
+2020-03-26 14:00:00+00:00,18.19
+2020-03-26 15:00:00+00:00,18.9
+2020-03-26 16:00:00+00:00,27.29
+2020-03-26 17:00:00+00:00,33.87
+2020-03-26 18:00:00+00:00,34.64
+2020-03-26 19:00:00+00:00,30.09
+2020-03-26 20:00:00+00:00,26.27
+2020-03-26 21:00:00+00:00,25.5
+2020-03-26 22:00:00+00:00,23.94
+2020-03-26 23:00:00+00:00,21.26
+2020-03-27 00:00:00+00:00,19.0
+2020-03-27 01:00:00+00:00,18.54
+2020-03-27 02:00:00+00:00,18.25
+2020-03-27 03:00:00+00:00,18.5
+2020-03-27 04:00:00+00:00,20.6
+2020-03-27 05:00:00+00:00,24.65
+2020-03-27 06:00:00+00:00,26.95
+2020-03-27 07:00:00+00:00,25.91
+2020-03-27 08:00:00+00:00,22.67
+2020-03-27 09:00:00+00:00,19.98
+2020-03-27 10:00:00+00:00,18.47
+2020-03-27 11:00:00+00:00,18.5
+2020-03-27 12:00:00+00:00,16.0
+2020-03-27 13:00:00+00:00,15.64
+2020-03-27 14:00:00+00:00,17.44
+2020-03-27 15:00:00+00:00,18.08
+2020-03-27 16:00:00+00:00,21.8
+2020-03-27 17:00:00+00:00,26.72
+2020-03-27 18:00:00+00:00,30.0
+2020-03-27 19:00:00+00:00,24.94
+2020-03-27 20:00:00+00:00,23.19
+2020-03-27 21:00:00+00:00,24.91
+2020-03-27 22:00:00+00:00,25.16
+2020-03-27 23:00:00+00:00,21.93
+2020-03-28 00:00:00+00:00,21.09
+2020-03-28 01:00:00+00:00,21.67
+2020-03-28 02:00:00+00:00,19.38
+2020-03-28 03:00:00+00:00,18.8
+2020-03-28 04:00:00+00:00,18.44
+2020-03-28 05:00:00+00:00,18.96
+2020-03-28 06:00:00+00:00,18.91
+2020-03-28 07:00:00+00:00,17.22
+2020-03-28 08:00:00+00:00,13.08
+2020-03-28 09:00:00+00:00,9.9
+2020-03-28 10:00:00+00:00,6.51
+2020-03-28 11:00:00+00:00,5.12
+2020-03-28 12:00:00+00:00,1.0
+2020-03-28 13:00:00+00:00,-0.72
+2020-03-28 14:00:00+00:00,0.02
+2020-03-28 15:00:00+00:00,5.77
+2020-03-28 16:00:00+00:00,17.14
+2020-03-28 17:00:00+00:00,19.97
+2020-03-28 18:00:00+00:00,21.93
+2020-03-28 19:00:00+00:00,17.02
+2020-03-28 20:00:00+00:00,16.39
+2020-03-28 21:00:00+00:00,16.27
+2020-03-28 22:00:00+00:00,16.0
+2020-03-28 23:00:00+00:00,11.76
+2020-03-29 00:00:00+00:00,11.05
+2020-03-29 01:00:00+00:00,6.6
+2020-03-29 04:00:00+00:00,0.08
+2020-03-29 05:00:00+00:00,0.96
+2020-03-29 06:00:00+00:00,2.59
+2020-03-29 07:00:00+00:00,2.93
+2020-03-29 08:00:00+00:00,-0.03
+2020-03-29 09:00:00+00:00,-0.08
+2020-03-29 10:00:00+00:00,-1.13
+2020-03-29 11:00:00+00:00,-10.87
+2020-03-29 12:00:00+00:00,-15.8
+2020-03-29 13:00:00+00:00,-10.79
+2020-03-29 14:00:00+00:00,-5.98
+2020-03-29 15:00:00+00:00,0.08
+2020-03-29 16:00:00+00:00,7.81
+2020-03-29 17:00:00+00:00,16.99
+2020-03-29 18:00:00+00:00,17.9
+2020-03-29 19:00:00+00:00,17.45
+2020-03-29 20:00:00+00:00,20.14
+2020-03-29 21:00:00+00:00,20.59
+2020-03-29 22:00:00+00:00,18.1
+2020-03-29 23:00:00+00:00,17.81
+2020-03-30 00:00:00+00:00,19.65
+2020-03-30 01:00:00+00:00,17.61
+2020-03-30 02:00:00+00:00,16.99
+2020-03-30 03:00:00+00:00,19.94
+2020-03-30 04:00:00+00:00,24.94
+2020-03-30 05:00:00+00:00,31.44
+2020-03-30 06:00:00+00:00,30.94
+2020-03-30 07:00:00+00:00,26.11
+2020-03-30 08:00:00+00:00,22.4
+2020-03-30 09:00:00+00:00,21.09
+2020-03-30 10:00:00+00:00,21.09
+2020-03-30 11:00:00+00:00,19.12
+2020-03-30 12:00:00+00:00,17.07
+2020-03-30 13:00:00+00:00,15.8
+2020-03-30 14:00:00+00:00,15.5
+2020-03-30 15:00:00+00:00,21.52
+2020-03-30 16:00:00+00:00,27.94
+2020-03-30 17:00:00+00:00,38.93
+2020-03-30 18:00:00+00:00,35.7
+2020-03-30 19:00:00+00:00,28.6
+2020-03-30 20:00:00+00:00,27.01
+2020-03-30 21:00:00+00:00,24.38
+2020-03-30 22:00:00+00:00,23.39
+2020-03-30 23:00:00+00:00,19.69
+2020-03-31 00:00:00+00:00,19.91
+2020-03-31 01:00:00+00:00,19.59
+2020-03-31 02:00:00+00:00,19.01
+2020-03-31 03:00:00+00:00,23.95
+2020-03-31 04:00:00+00:00,30.97
+2020-03-31 05:00:00+00:00,42.3
+2020-03-31 06:00:00+00:00,35.11
+2020-03-31 07:00:00+00:00,25.75
+2020-03-31 08:00:00+00:00,23.94
+2020-03-31 09:00:00+00:00,19.78
+2020-03-31 10:00:00+00:00,20.0
+2020-03-31 11:00:00+00:00,18.39
+2020-03-31 12:00:00+00:00,17.5
+2020-03-31 13:00:00+00:00,17.6
+2020-03-31 14:00:00+00:00,17.86
+2020-03-31 15:00:00+00:00,24.03
+2020-03-31 16:00:00+00:00,31.44
+2020-03-31 17:00:00+00:00,42.66
+2020-03-31 18:00:00+00:00,33.53
+2020-03-31 19:00:00+00:00,26.97
+2020-03-31 20:00:00+00:00,26.61
+2020-03-31 21:00:00+00:00,24.1
+2020-03-31 22:00:00+00:00,22.26
+2020-03-31 23:00:00+00:00,20.22
+2020-04-01 00:00:00+00:00,19.67
+2020-04-01 01:00:00+00:00,19.25
+2020-04-01 02:00:00+00:00,19.31
+2020-04-01 03:00:00+00:00,20.76
+2020-04-01 04:00:00+00:00,25.43
+2020-04-01 05:00:00+00:00,27.21
+2020-04-01 06:00:00+00:00,27.96
+2020-04-01 07:00:00+00:00,25.5
+2020-04-01 08:00:00+00:00,21.97
+2020-04-01 09:00:00+00:00,20.27
+2020-04-01 10:00:00+00:00,19.35
+2020-04-01 11:00:00+00:00,18.25
+2020-04-01 12:00:00+00:00,17.3
+2020-04-01 13:00:00+00:00,18.09
+2020-04-01 14:00:00+00:00,19.11
+2020-04-01 15:00:00+00:00,22.01
+2020-04-01 16:00:00+00:00,26.9
+2020-04-01 17:00:00+00:00,31.27
+2020-04-01 18:00:00+00:00,34.97
+2020-04-01 19:00:00+00:00,28.94
+2020-04-01 20:00:00+00:00,28.31
+2020-04-01 21:00:00+00:00,26.35
+2020-04-01 22:00:00+00:00,24.18
+2020-04-01 23:00:00+00:00,22.93
+2020-04-02 00:00:00+00:00,21.8
+2020-04-02 01:00:00+00:00,20.96
+2020-04-02 02:00:00+00:00,20.8
+2020-04-02 03:00:00+00:00,22.56
+2020-04-02 04:00:00+00:00,25.31
+2020-04-02 05:00:00+00:00,27.31
+2020-04-02 06:00:00+00:00,27.8
+2020-04-02 07:00:00+00:00,25.0
+2020-04-02 08:00:00+00:00,21.1
+2020-04-02 09:00:00+00:00,18.65
+2020-04-02 10:00:00+00:00,12.42
+2020-04-02 11:00:00+00:00,9.06
+2020-04-02 12:00:00+00:00,4.64
+2020-04-02 13:00:00+00:00,4.62
+2020-04-02 14:00:00+00:00,6.65
+2020-04-02 15:00:00+00:00,17.2
+2020-04-02 16:00:00+00:00,22.71
+2020-04-02 17:00:00+00:00,25.82
+2020-04-02 18:00:00+00:00,27.3
+2020-04-02 19:00:00+00:00,24.47
+2020-04-02 20:00:00+00:00,25.0
+2020-04-02 21:00:00+00:00,20.55
+2020-04-02 22:00:00+00:00,21.69
+2020-04-02 23:00:00+00:00,18.93
+2020-04-03 00:00:00+00:00,18.15
+2020-04-03 01:00:00+00:00,18.19
+2020-04-03 02:00:00+00:00,18.47
+2020-04-03 03:00:00+00:00,18.45
+2020-04-03 04:00:00+00:00,23.76
+2020-04-03 05:00:00+00:00,26.1
+2020-04-03 06:00:00+00:00,26.45
+2020-04-03 07:00:00+00:00,25.5
+2020-04-03 08:00:00+00:00,23.03
+2020-04-03 09:00:00+00:00,21.04
+2020-04-03 10:00:00+00:00,20.24
+2020-04-03 11:00:00+00:00,17.7
+2020-04-03 12:00:00+00:00,17.08
+2020-04-03 13:00:00+00:00,17.03
+2020-04-03 14:00:00+00:00,17.07
+2020-04-03 15:00:00+00:00,19.98
+2020-04-03 16:00:00+00:00,25.57
+2020-04-03 17:00:00+00:00,28.44
+2020-04-03 18:00:00+00:00,33.54
+2020-04-03 19:00:00+00:00,27.23
+2020-04-03 20:00:00+00:00,29.15
+2020-04-03 21:00:00+00:00,28.0
+2020-04-03 22:00:00+00:00,25.1
+2020-04-03 23:00:00+00:00,22.99
+2020-04-04 00:00:00+00:00,21.1
+2020-04-04 01:00:00+00:00,20.1
+2020-04-04 02:00:00+00:00,19.8
+2020-04-04 03:00:00+00:00,19.6
+2020-04-04 04:00:00+00:00,21.79
+2020-04-04 05:00:00+00:00,22.97
+2020-04-04 06:00:00+00:00,21.97
+2020-04-04 07:00:00+00:00,19.0
+2020-04-04 08:00:00+00:00,14.98
+2020-04-04 09:00:00+00:00,13.06
+2020-04-04 10:00:00+00:00,14.28
+2020-04-04 11:00:00+00:00,10.82
+2020-04-04 12:00:00+00:00,10.0
+2020-04-04 13:00:00+00:00,9.88
+2020-04-04 14:00:00+00:00,15.74
+2020-04-04 15:00:00+00:00,21.51
+2020-04-04 16:00:00+00:00,26.84
+2020-04-04 17:00:00+00:00,36.75
+2020-04-04 18:00:00+00:00,32.67
+2020-04-04 19:00:00+00:00,23.93
+2020-04-04 20:00:00+00:00,21.54
+2020-04-04 21:00:00+00:00,17.07
+2020-04-04 22:00:00+00:00,17.99
+2020-04-04 23:00:00+00:00,11.4
+2020-04-05 00:00:00+00:00,9.82
+2020-04-05 01:00:00+00:00,9.9
+2020-04-05 02:00:00+00:00,8.17
+2020-04-05 03:00:00+00:00,5.26
+2020-04-05 04:00:00+00:00,5.53
+2020-04-05 05:00:00+00:00,5.5
+2020-04-05 06:00:00+00:00,8.05
+2020-04-05 07:00:00+00:00,5.77
+2020-04-05 08:00:00+00:00,4.55
+2020-04-05 09:00:00+00:00,1.36
+2020-04-05 10:00:00+00:00,-1.85
+2020-04-05 11:00:00+00:00,-31.95
+2020-04-05 12:00:00+00:00,-50.26
+2020-04-05 13:00:00+00:00,-30.29
+2020-04-05 14:00:00+00:00,-4.95
+2020-04-05 15:00:00+00:00,4.48
+2020-04-05 16:00:00+00:00,16.51
+2020-04-05 17:00:00+00:00,19.9
+2020-04-05 18:00:00+00:00,18.48
+2020-04-05 19:00:00+00:00,10.39
+2020-04-05 20:00:00+00:00,11.95
+2020-04-05 21:00:00+00:00,8.65
+2020-04-05 22:00:00+00:00,6.66
+2020-04-05 23:00:00+00:00,4.28
+2020-04-06 00:00:00+00:00,6.34
+2020-04-06 01:00:00+00:00,3.7
+2020-04-06 02:00:00+00:00,3.66
+2020-04-06 03:00:00+00:00,5.09
+2020-04-06 04:00:00+00:00,11.89
+2020-04-06 05:00:00+00:00,21.81
+2020-04-06 06:00:00+00:00,21.63
+2020-04-06 07:00:00+00:00,18.73
+2020-04-06 08:00:00+00:00,14.54
+2020-04-06 09:00:00+00:00,11.19
+2020-04-06 10:00:00+00:00,14.02
+2020-04-06 11:00:00+00:00,10.55
+2020-04-06 12:00:00+00:00,10.0
+2020-04-06 13:00:00+00:00,11.83
+2020-04-06 14:00:00+00:00,14.83
+2020-04-06 15:00:00+00:00,21.68
+2020-04-06 16:00:00+00:00,31.01
+2020-04-06 17:00:00+00:00,43.33
+2020-04-06 18:00:00+00:00,45.33
+2020-04-06 19:00:00+00:00,30.86
+2020-04-06 20:00:00+00:00,28.92
+2020-04-06 21:00:00+00:00,24.17
+2020-04-06 22:00:00+00:00,20.05
+2020-04-06 23:00:00+00:00,19.97
+2020-04-07 00:00:00+00:00,20.61
+2020-04-07 01:00:00+00:00,20.48
+2020-04-07 02:00:00+00:00,21.65
+2020-04-07 03:00:00+00:00,23.86
+2020-04-07 04:00:00+00:00,31.98
+2020-04-07 05:00:00+00:00,34.91
+2020-04-07 06:00:00+00:00,31.32
+2020-04-07 07:00:00+00:00,23.66
+2020-04-07 08:00:00+00:00,19.19
+2020-04-07 09:00:00+00:00,18.05
+2020-04-07 10:00:00+00:00,17.55
+2020-04-07 11:00:00+00:00,13.52
+2020-04-07 12:00:00+00:00,12.89
+2020-04-07 13:00:00+00:00,15.48
+2020-04-07 14:00:00+00:00,18.0
+2020-04-07 15:00:00+00:00,22.66
+2020-04-07 16:00:00+00:00,31.42
+2020-04-07 17:00:00+00:00,40.1
+2020-04-07 18:00:00+00:00,37.31
+2020-04-07 19:00:00+00:00,27.4
+2020-04-07 20:00:00+00:00,23.84
+2020-04-07 21:00:00+00:00,19.05
+2020-04-07 22:00:00+00:00,21.17
+2020-04-07 23:00:00+00:00,20.53
+2020-04-08 00:00:00+00:00,19.72
+2020-04-08 01:00:00+00:00,19.87
+2020-04-08 02:00:00+00:00,20.09
+2020-04-08 03:00:00+00:00,23.15
+2020-04-08 04:00:00+00:00,29.33
+2020-04-08 05:00:00+00:00,29.7
+2020-04-08 06:00:00+00:00,29.08
+2020-04-08 07:00:00+00:00,25.91
+2020-04-08 08:00:00+00:00,21.95
+2020-04-08 09:00:00+00:00,21.69
+2020-04-08 10:00:00+00:00,19.08
+2020-04-08 11:00:00+00:00,17.92
+2020-04-08 12:00:00+00:00,17.57
+2020-04-08 13:00:00+00:00,19.54
+2020-04-08 14:00:00+00:00,21.55
+2020-04-08 15:00:00+00:00,25.9
+2020-04-08 16:00:00+00:00,35.31
+2020-04-08 17:00:00+00:00,49.12
+2020-04-08 18:00:00+00:00,50.33
+2020-04-08 19:00:00+00:00,39.03
+2020-04-08 20:00:00+00:00,31.41
+2020-04-08 21:00:00+00:00,27.34
+2020-04-08 22:00:00+00:00,22.66
+2020-04-08 23:00:00+00:00,21.3
+2020-04-09 00:00:00+00:00,21.08
+2020-04-09 01:00:00+00:00,20.9
+2020-04-09 02:00:00+00:00,20.51
+2020-04-09 03:00:00+00:00,22.68
+2020-04-09 04:00:00+00:00,27.66
+2020-04-09 05:00:00+00:00,29.7
+2020-04-09 06:00:00+00:00,29.53
+2020-04-09 07:00:00+00:00,25.21
+2020-04-09 08:00:00+00:00,22.43
+2020-04-09 09:00:00+00:00,21.26
+2020-04-09 10:00:00+00:00,19.42
+2020-04-09 11:00:00+00:00,17.4
+2020-04-09 12:00:00+00:00,13.19
+2020-04-09 13:00:00+00:00,16.41
+2020-04-09 14:00:00+00:00,17.88
+2020-04-09 15:00:00+00:00,23.18
+2020-04-09 16:00:00+00:00,26.58
+2020-04-09 17:00:00+00:00,30.92
+2020-04-09 18:00:00+00:00,31.43
+2020-04-09 19:00:00+00:00,30.0
+2020-04-09 20:00:00+00:00,27.92
+2020-04-09 21:00:00+00:00,25.0
+2020-04-09 22:00:00+00:00,25.11
+2020-04-09 23:00:00+00:00,25.02
+2020-04-10 00:00:00+00:00,22.0
+2020-04-10 01:00:00+00:00,24.59
+2020-04-10 02:00:00+00:00,26.37
+2020-04-10 03:00:00+00:00,26.86
+2020-04-10 04:00:00+00:00,27.06
+2020-04-10 05:00:00+00:00,28.57
+2020-04-10 06:00:00+00:00,28.0
+2020-04-10 07:00:00+00:00,24.58
+2020-04-10 08:00:00+00:00,18.04
+2020-04-10 09:00:00+00:00,17.06
+2020-04-10 10:00:00+00:00,13.97
+2020-04-10 11:00:00+00:00,10.55
+2020-04-10 12:00:00+00:00,9.16
+2020-04-10 13:00:00+00:00,10.03
+2020-04-10 14:00:00+00:00,14.0
+2020-04-10 15:00:00+00:00,24.54
+2020-04-10 16:00:00+00:00,27.0
+2020-04-10 17:00:00+00:00,31.43
+2020-04-10 18:00:00+00:00,34.83
+2020-04-10 19:00:00+00:00,31.57
+2020-04-10 20:00:00+00:00,29.81
+2020-04-10 21:00:00+00:00,25.18
+2020-04-10 22:00:00+00:00,24.19
+2020-04-10 23:00:00+00:00,21.84
+2020-04-11 00:00:00+00:00,20.1
+2020-04-11 01:00:00+00:00,21.11
+2020-04-11 02:00:00+00:00,23.01
+2020-04-11 03:00:00+00:00,24.72
+2020-04-11 04:00:00+00:00,24.92
+2020-04-11 05:00:00+00:00,25.16
+2020-04-11 06:00:00+00:00,25.04
+2020-04-11 07:00:00+00:00,20.82
+2020-04-11 08:00:00+00:00,14.3
+2020-04-11 09:00:00+00:00,11.59
+2020-04-11 10:00:00+00:00,12.33
+2020-04-11 11:00:00+00:00,8.6
+2020-04-11 12:00:00+00:00,5.1
+2020-04-11 13:00:00+00:00,7.28
+2020-04-11 14:00:00+00:00,14.01
+2020-04-11 15:00:00+00:00,20.0
+2020-04-11 16:00:00+00:00,28.97
+2020-04-11 17:00:00+00:00,35.11
+2020-04-11 18:00:00+00:00,35.95
+2020-04-11 19:00:00+00:00,29.66
+2020-04-11 20:00:00+00:00,24.91
+2020-04-11 21:00:00+00:00,21.82
+2020-04-11 22:00:00+00:00,21.8
+2020-04-11 23:00:00+00:00,19.01
+2020-04-12 00:00:00+00:00,16.71
+2020-04-12 01:00:00+00:00,14.38
+2020-04-12 02:00:00+00:00,14.06
+2020-04-12 03:00:00+00:00,15.02
+2020-04-12 04:00:00+00:00,15.74
+2020-04-12 05:00:00+00:00,16.0
+2020-04-12 06:00:00+00:00,14.06
+2020-04-12 07:00:00+00:00,9.99
+2020-04-12 08:00:00+00:00,5.18
+2020-04-12 09:00:00+00:00,4.93
+2020-04-12 10:00:00+00:00,4.98
+2020-04-12 11:00:00+00:00,1.84
+2020-04-12 12:00:00+00:00,0.0
+2020-04-12 13:00:00+00:00,0.17
+2020-04-12 14:00:00+00:00,3.0
+2020-04-12 15:00:00+00:00,4.14
+2020-04-12 16:00:00+00:00,18.13
+2020-04-12 17:00:00+00:00,25.17
+2020-04-12 18:00:00+00:00,24.82
+2020-04-12 19:00:00+00:00,21.97
+2020-04-12 20:00:00+00:00,19.5
+2020-04-12 21:00:00+00:00,8.2
+2020-04-12 22:00:00+00:00,10.34
+2020-04-12 23:00:00+00:00,0.07
+2020-04-13 00:00:00+00:00,1.72
+2020-04-13 01:00:00+00:00,0.77
+2020-04-13 02:00:00+00:00,0.02
+2020-04-13 03:00:00+00:00,-0.09
+2020-04-13 04:00:00+00:00,-2.35
+2020-04-13 05:00:00+00:00,-5.0
+2020-04-13 06:00:00+00:00,-5.91
+2020-04-13 07:00:00+00:00,-4.94
+2020-04-13 08:00:00+00:00,-5.09
+2020-04-13 09:00:00+00:00,-19.91
+2020-04-13 10:00:00+00:00,-55.62
+2020-04-13 11:00:00+00:00,-70.1
+2020-04-13 12:00:00+00:00,-78.0
+2020-04-13 13:00:00+00:00,-78.15
+2020-04-13 14:00:00+00:00,-74.97
+2020-04-13 15:00:00+00:00,-39.94
+2020-04-13 16:00:00+00:00,-1.77
+2020-04-13 17:00:00+00:00,11.21
+2020-04-13 18:00:00+00:00,9.76
+2020-04-13 19:00:00+00:00,6.45
+2020-04-13 20:00:00+00:00,9.29
+2020-04-13 21:00:00+00:00,9.02
+2020-04-13 22:00:00+00:00,3.79
+2020-04-13 23:00:00+00:00,4.4
+2020-04-14 00:00:00+00:00,3.9
+2020-04-14 01:00:00+00:00,3.96
+2020-04-14 02:00:00+00:00,4.6
+2020-04-14 03:00:00+00:00,15.88
+2020-04-14 04:00:00+00:00,25.24
+2020-04-14 05:00:00+00:00,32.74
+2020-04-14 06:00:00+00:00,31.14
+2020-04-14 07:00:00+00:00,23.68
+2020-04-14 08:00:00+00:00,21.86
+2020-04-14 09:00:00+00:00,19.73
+2020-04-14 10:00:00+00:00,17.13
+2020-04-14 11:00:00+00:00,16.12
+2020-04-14 12:00:00+00:00,13.54
+2020-04-14 13:00:00+00:00,15.03
+2020-04-14 14:00:00+00:00,19.1
+2020-04-14 15:00:00+00:00,23.15
+2020-04-14 16:00:00+00:00,26.82
+2020-04-14 17:00:00+00:00,33.38
+2020-04-14 18:00:00+00:00,39.91
+2020-04-14 19:00:00+00:00,31.45
+2020-04-14 20:00:00+00:00,26.77
+2020-04-14 21:00:00+00:00,24.28
+2020-04-14 22:00:00+00:00,19.87
+2020-04-14 23:00:00+00:00,17.08
+2020-04-15 00:00:00+00:00,17.0
+2020-04-15 01:00:00+00:00,16.37
+2020-04-15 02:00:00+00:00,16.57
+2020-04-15 03:00:00+00:00,19.1
+2020-04-15 04:00:00+00:00,25.15
+2020-04-15 05:00:00+00:00,26.09
+2020-04-15 06:00:00+00:00,24.99
+2020-04-15 07:00:00+00:00,21.2
+2020-04-15 08:00:00+00:00,14.29
+2020-04-15 09:00:00+00:00,14.16
+2020-04-15 10:00:00+00:00,8.07
+2020-04-15 11:00:00+00:00,8.0
+2020-04-15 12:00:00+00:00,4.46
+2020-04-15 13:00:00+00:00,8.05
+2020-04-15 14:00:00+00:00,12.13
+2020-04-15 15:00:00+00:00,21.85
+2020-04-15 16:00:00+00:00,27.34
+2020-04-15 17:00:00+00:00,37.84
+2020-04-15 18:00:00+00:00,41.91
+2020-04-15 19:00:00+00:00,31.34
+2020-04-15 20:00:00+00:00,26.25
+2020-04-15 21:00:00+00:00,24.99
+2020-04-15 22:00:00+00:00,20.81
+2020-04-15 23:00:00+00:00,20.61
+2020-04-16 00:00:00+00:00,21.02
+2020-04-16 01:00:00+00:00,21.1
+2020-04-16 02:00:00+00:00,21.1
+2020-04-16 03:00:00+00:00,23.73
+2020-04-16 04:00:00+00:00,26.96
+2020-04-16 05:00:00+00:00,35.01
+2020-04-16 06:00:00+00:00,30.98
+2020-04-16 07:00:00+00:00,25.0
+2020-04-16 08:00:00+00:00,21.5
+2020-04-16 09:00:00+00:00,19.49
+2020-04-16 10:00:00+00:00,16.23
+2020-04-16 11:00:00+00:00,15.29
+2020-04-16 12:00:00+00:00,15.1
+2020-04-16 13:00:00+00:00,16.29
+2020-04-16 14:00:00+00:00,19.32
+2020-04-16 15:00:00+00:00,24.99
+2020-04-16 16:00:00+00:00,29.34
+2020-04-16 17:00:00+00:00,46.39
+2020-04-16 18:00:00+00:00,53.25
+2020-04-16 19:00:00+00:00,33.37
+2020-04-16 20:00:00+00:00,27.01
+2020-04-16 21:00:00+00:00,23.71
+2020-04-16 22:00:00+00:00,22.08
+2020-04-16 23:00:00+00:00,21.58
+2020-04-17 00:00:00+00:00,21.06
+2020-04-17 01:00:00+00:00,21.99
+2020-04-17 02:00:00+00:00,22.44
+2020-04-17 03:00:00+00:00,24.41
+2020-04-17 04:00:00+00:00,32.93
+2020-04-17 05:00:00+00:00,47.84
+2020-04-17 06:00:00+00:00,44.81
+2020-04-17 07:00:00+00:00,26.41
+2020-04-17 08:00:00+00:00,24.9
+2020-04-17 09:00:00+00:00,23.87
+2020-04-17 10:00:00+00:00,20.44
+2020-04-17 11:00:00+00:00,18.07
+2020-04-17 12:00:00+00:00,18.54
+2020-04-17 13:00:00+00:00,21.87
+2020-04-17 14:00:00+00:00,21.75
+2020-04-17 15:00:00+00:00,25.15
+2020-04-17 16:00:00+00:00,36.76
+2020-04-17 17:00:00+00:00,48.75
+2020-04-17 18:00:00+00:00,42.77
+2020-04-17 19:00:00+00:00,32.38
+2020-04-17 20:00:00+00:00,24.92
+2020-04-17 21:00:00+00:00,20.76
+2020-04-17 22:00:00+00:00,22.1
+2020-04-17 23:00:00+00:00,20.13
+2020-04-18 00:00:00+00:00,18.78
+2020-04-18 01:00:00+00:00,18.1
+2020-04-18 02:00:00+00:00,18.55
+2020-04-18 03:00:00+00:00,19.07
+2020-04-18 04:00:00+00:00,21.62
+2020-04-18 05:00:00+00:00,23.82
+2020-04-18 06:00:00+00:00,23.87
+2020-04-18 07:00:00+00:00,24.33
+2020-04-18 08:00:00+00:00,17.3
+2020-04-18 09:00:00+00:00,16.63
+2020-04-18 10:00:00+00:00,16.8
+2020-04-18 11:00:00+00:00,12.84
+2020-04-18 12:00:00+00:00,12.32
+2020-04-18 13:00:00+00:00,12.77
+2020-04-18 14:00:00+00:00,15.05
+2020-04-18 15:00:00+00:00,24.13
+2020-04-18 16:00:00+00:00,25.99
+2020-04-18 17:00:00+00:00,29.42
+2020-04-18 18:00:00+00:00,28.66
+2020-04-18 19:00:00+00:00,23.81
+2020-04-18 20:00:00+00:00,21.16
+2020-04-18 21:00:00+00:00,18.38
+2020-04-18 22:00:00+00:00,16.51
+2020-04-18 23:00:00+00:00,13.71
+2020-04-19 00:00:00+00:00,12.12
+2020-04-19 01:00:00+00:00,9.3
+2020-04-19 02:00:00+00:00,10.98
+2020-04-19 03:00:00+00:00,11.31
+2020-04-19 04:00:00+00:00,11.66
+2020-04-19 05:00:00+00:00,11.15
+2020-04-19 06:00:00+00:00,14.01
+2020-04-19 07:00:00+00:00,12.47
+2020-04-19 08:00:00+00:00,10.88
+2020-04-19 09:00:00+00:00,8.39
+2020-04-19 10:00:00+00:00,9.21
+2020-04-19 11:00:00+00:00,0.03
+2020-04-19 12:00:00+00:00,-18.5
+2020-04-19 13:00:00+00:00,-26.0
+2020-04-19 14:00:00+00:00,-11.84
+2020-04-19 15:00:00+00:00,4.99
+2020-04-19 16:00:00+00:00,11.2
+2020-04-19 17:00:00+00:00,15.42
+2020-04-19 18:00:00+00:00,15.59
+2020-04-19 19:00:00+00:00,12.73
+2020-04-19 20:00:00+00:00,12.34
+2020-04-19 21:00:00+00:00,10.19
+2020-04-19 22:00:00+00:00,4.43
+2020-04-19 23:00:00+00:00,4.38
+2020-04-20 00:00:00+00:00,3.69
+2020-04-20 01:00:00+00:00,0.66
+2020-04-20 02:00:00+00:00,0.03
+2020-04-20 03:00:00+00:00,4.78
+2020-04-20 04:00:00+00:00,18.0
+2020-04-20 05:00:00+00:00,22.82
+2020-04-20 06:00:00+00:00,22.93
+2020-04-20 07:00:00+00:00,16.07
+2020-04-20 08:00:00+00:00,11.72
+2020-04-20 09:00:00+00:00,5.46
+2020-04-20 10:00:00+00:00,-4.98
+2020-04-20 11:00:00+00:00,-29.7
+2020-04-20 12:00:00+00:00,-44.25
+2020-04-20 13:00:00+00:00,-39.49
+2020-04-20 14:00:00+00:00,-23.71
+2020-04-20 15:00:00+00:00,4.01
+2020-04-20 16:00:00+00:00,16.38
+2020-04-20 17:00:00+00:00,17.81
+2020-04-20 18:00:00+00:00,18.38
+2020-04-20 19:00:00+00:00,14.05
+2020-04-20 20:00:00+00:00,10.28
+2020-04-20 21:00:00+00:00,4.85
+2020-04-20 22:00:00+00:00,4.65
+2020-04-20 23:00:00+00:00,4.31
+2020-04-21 00:00:00+00:00,3.69
+2020-04-21 01:00:00+00:00,-0.59
+2020-04-21 02:00:00+00:00,3.72
+2020-04-21 03:00:00+00:00,4.73
+2020-04-21 04:00:00+00:00,10.0
+2020-04-21 05:00:00+00:00,16.13
+2020-04-21 06:00:00+00:00,16.52
+2020-04-21 07:00:00+00:00,7.92
+2020-04-21 08:00:00+00:00,-19.21
+2020-04-21 09:00:00+00:00,-69.05
+2020-04-21 10:00:00+00:00,-79.74
+2020-04-21 11:00:00+00:00,-80.09
+2020-04-21 12:00:00+00:00,-83.94
+2020-04-21 13:00:00+00:00,-80.02
+2020-04-21 14:00:00+00:00,-78.09
+2020-04-21 15:00:00+00:00,-23.12
+2020-04-21 16:00:00+00:00,5.53
+2020-04-21 17:00:00+00:00,10.99
+2020-04-21 18:00:00+00:00,10.99
+2020-04-21 19:00:00+00:00,11.17
+2020-04-21 20:00:00+00:00,7.6
+2020-04-21 21:00:00+00:00,8.31
+2020-04-21 22:00:00+00:00,4.39
+2020-04-21 23:00:00+00:00,4.12
+2020-04-22 00:00:00+00:00,3.5
+2020-04-22 01:00:00+00:00,4.14
+2020-04-22 02:00:00+00:00,4.57
+2020-04-22 03:00:00+00:00,6.0
+2020-04-22 04:00:00+00:00,14.92
+2020-04-22 05:00:00+00:00,23.39
+2020-04-22 06:00:00+00:00,19.81
+2020-04-22 07:00:00+00:00,10.57
+2020-04-22 08:00:00+00:00,6.77
+2020-04-22 09:00:00+00:00,6.1
+2020-04-22 10:00:00+00:00,-0.56
+2020-04-22 11:00:00+00:00,-24.97
+2020-04-22 12:00:00+00:00,-29.98
+2020-04-22 13:00:00+00:00,-5.76
+2020-04-22 14:00:00+00:00,4.07
+2020-04-22 15:00:00+00:00,8.59
+2020-04-22 16:00:00+00:00,18.05
+2020-04-22 17:00:00+00:00,24.57
+2020-04-22 18:00:00+00:00,25.54
+2020-04-22 19:00:00+00:00,22.19
+2020-04-22 20:00:00+00:00,20.01
+2020-04-22 21:00:00+00:00,19.0
+2020-04-22 22:00:00+00:00,20.1
+2020-04-22 23:00:00+00:00,19.68
+2020-04-23 00:00:00+00:00,18.38
+2020-04-23 01:00:00+00:00,20.07
+2020-04-23 02:00:00+00:00,20.6
+2020-04-23 03:00:00+00:00,22.34
+2020-04-23 04:00:00+00:00,33.7
+2020-04-23 05:00:00+00:00,42.03
+2020-04-23 06:00:00+00:00,38.48
+2020-04-23 07:00:00+00:00,23.72
+2020-04-23 08:00:00+00:00,18.18
+2020-04-23 09:00:00+00:00,17.4
+2020-04-23 10:00:00+00:00,16.95
+2020-04-23 11:00:00+00:00,16.63
+2020-04-23 12:00:00+00:00,14.95
+2020-04-23 13:00:00+00:00,14.97
+2020-04-23 14:00:00+00:00,18.11
+2020-04-23 15:00:00+00:00,25.07
+2020-04-23 16:00:00+00:00,34.51
+2020-04-23 17:00:00+00:00,58.95
+2020-04-23 18:00:00+00:00,69.68
+2020-04-23 19:00:00+00:00,38.62
+2020-04-23 20:00:00+00:00,34.43
+2020-04-23 21:00:00+00:00,28.6
+2020-04-23 22:00:00+00:00,23.87
+2020-04-23 23:00:00+00:00,21.63
+2020-04-24 00:00:00+00:00,21.54
+2020-04-24 01:00:00+00:00,21.54
+2020-04-24 02:00:00+00:00,20.93
+2020-04-24 03:00:00+00:00,22.0
+2020-04-24 04:00:00+00:00,26.69
+2020-04-24 05:00:00+00:00,35.85
+2020-04-24 06:00:00+00:00,31.0
+2020-04-24 07:00:00+00:00,21.84
+2020-04-24 08:00:00+00:00,20.0
+2020-04-24 09:00:00+00:00,18.45
+2020-04-24 10:00:00+00:00,16.15
+2020-04-24 11:00:00+00:00,14.55
+2020-04-24 12:00:00+00:00,12.02
+2020-04-24 13:00:00+00:00,10.0
+2020-04-24 14:00:00+00:00,11.81
+2020-04-24 15:00:00+00:00,15.62
+2020-04-24 16:00:00+00:00,19.97
+2020-04-24 17:00:00+00:00,22.27
+2020-04-24 18:00:00+00:00,22.5
+2020-04-24 19:00:00+00:00,21.98
+2020-04-24 20:00:00+00:00,23.0
+2020-04-24 21:00:00+00:00,20.4
+2020-04-24 22:00:00+00:00,12.9
+2020-04-24 23:00:00+00:00,9.07
+2020-04-25 00:00:00+00:00,12.61
+2020-04-25 01:00:00+00:00,14.42
+2020-04-25 02:00:00+00:00,14.48
+2020-04-25 03:00:00+00:00,14.03
+2020-04-25 04:00:00+00:00,14.88
+2020-04-25 05:00:00+00:00,15.09
+2020-04-25 06:00:00+00:00,18.7
+2020-04-25 07:00:00+00:00,16.63
+2020-04-25 08:00:00+00:00,16.03
+2020-04-25 09:00:00+00:00,16.3
+2020-04-25 10:00:00+00:00,15.08
+2020-04-25 11:00:00+00:00,12.25
+2020-04-25 12:00:00+00:00,7.76
+2020-04-25 13:00:00+00:00,7.99
+2020-04-25 14:00:00+00:00,10.07
+2020-04-25 15:00:00+00:00,16.62
+2020-04-25 16:00:00+00:00,23.51
+2020-04-25 17:00:00+00:00,26.7
+2020-04-25 18:00:00+00:00,32.0
+2020-04-25 19:00:00+00:00,29.77
+2020-04-25 20:00:00+00:00,25.69
+2020-04-25 21:00:00+00:00,22.11
+2020-04-25 22:00:00+00:00,22.3
+2020-04-25 23:00:00+00:00,19.79
+2020-04-26 00:00:00+00:00,20.76
+2020-04-26 01:00:00+00:00,21.06
+2020-04-26 02:00:00+00:00,22.23
+2020-04-26 03:00:00+00:00,21.95
+2020-04-26 04:00:00+00:00,18.81
+2020-04-26 05:00:00+00:00,18.09
+2020-04-26 06:00:00+00:00,16.06
+2020-04-26 07:00:00+00:00,15.01
+2020-04-26 08:00:00+00:00,13.0
+2020-04-26 09:00:00+00:00,14.38
+2020-04-26 10:00:00+00:00,15.0
+2020-04-26 11:00:00+00:00,11.9
+2020-04-26 12:00:00+00:00,5.56
+2020-04-26 13:00:00+00:00,6.93
+2020-04-26 14:00:00+00:00,12.42
+2020-04-26 15:00:00+00:00,16.15
+2020-04-26 16:00:00+00:00,24.82
+2020-04-26 17:00:00+00:00,27.97
+2020-04-26 18:00:00+00:00,31.84
+2020-04-26 19:00:00+00:00,27.49
+2020-04-26 20:00:00+00:00,26.06
+2020-04-26 21:00:00+00:00,23.76
+2020-04-26 22:00:00+00:00,20.84
+2020-04-26 23:00:00+00:00,21.11
+2020-04-27 00:00:00+00:00,19.08
+2020-04-27 01:00:00+00:00,19.34
+2020-04-27 02:00:00+00:00,20.23
+2020-04-27 03:00:00+00:00,21.61
+2020-04-27 04:00:00+00:00,25.95
+2020-04-27 05:00:00+00:00,28.0
+2020-04-27 06:00:00+00:00,25.9
+2020-04-27 07:00:00+00:00,21.99
+2020-04-27 08:00:00+00:00,21.17
+2020-04-27 09:00:00+00:00,20.64
+2020-04-27 10:00:00+00:00,21.92
+2020-04-27 11:00:00+00:00,20.39
+2020-04-27 12:00:00+00:00,19.85
+2020-04-27 13:00:00+00:00,18.42
+2020-04-27 14:00:00+00:00,18.4
+2020-04-27 15:00:00+00:00,24.92
+2020-04-27 16:00:00+00:00,32.96
+2020-04-27 17:00:00+00:00,48.31
+2020-04-27 18:00:00+00:00,45.56
+2020-04-27 19:00:00+00:00,38.56
+2020-04-27 20:00:00+00:00,32.1
+2020-04-27 21:00:00+00:00,24.74
+2020-04-27 22:00:00+00:00,22.21
+2020-04-27 23:00:00+00:00,20.27
+2020-04-28 00:00:00+00:00,20.42
+2020-04-28 01:00:00+00:00,20.16
+2020-04-28 02:00:00+00:00,20.61
+2020-04-28 03:00:00+00:00,21.94
+2020-04-28 04:00:00+00:00,25.94
+2020-04-28 05:00:00+00:00,27.94
+2020-04-28 06:00:00+00:00,28.72
+2020-04-28 07:00:00+00:00,27.95
+2020-04-28 08:00:00+00:00,26.16
+2020-04-28 09:00:00+00:00,25.83
+2020-04-28 10:00:00+00:00,24.93
+2020-04-28 11:00:00+00:00,24.06
+2020-04-28 12:00:00+00:00,24.89
+2020-04-28 13:00:00+00:00,24.85
+2020-04-28 14:00:00+00:00,24.81
+2020-04-28 15:00:00+00:00,27.18
+2020-04-28 16:00:00+00:00,28.74
+2020-04-28 17:00:00+00:00,31.28
+2020-04-28 18:00:00+00:00,29.99
+2020-04-28 19:00:00+00:00,27.44
+2020-04-28 20:00:00+00:00,24.09
+2020-04-28 21:00:00+00:00,21.03
+2020-04-28 22:00:00+00:00,19.04
+2020-04-28 23:00:00+00:00,17.58
+2020-04-29 00:00:00+00:00,17.09
+2020-04-29 01:00:00+00:00,17.11
+2020-04-29 02:00:00+00:00,18.04
+2020-04-29 03:00:00+00:00,20.91
+2020-04-29 04:00:00+00:00,24.28
+2020-04-29 05:00:00+00:00,27.09
+2020-04-29 06:00:00+00:00,30.57
+2020-04-29 07:00:00+00:00,30.24
+2020-04-29 08:00:00+00:00,27.98
+2020-04-29 09:00:00+00:00,26.0
+2020-04-29 10:00:00+00:00,23.49
+2020-04-29 11:00:00+00:00,19.08
+2020-04-29 12:00:00+00:00,18.0
+2020-04-29 13:00:00+00:00,17.7
+2020-04-29 14:00:00+00:00,19.01
+2020-04-29 15:00:00+00:00,21.59
+2020-04-29 16:00:00+00:00,26.46
+2020-04-29 17:00:00+00:00,28.7
+2020-04-29 18:00:00+00:00,30.85
+2020-04-29 19:00:00+00:00,27.81
+2020-04-29 20:00:00+00:00,23.69
+2020-04-29 21:00:00+00:00,20.96
+2020-04-29 22:00:00+00:00,17.55
+2020-04-29 23:00:00+00:00,15.57
+2020-04-30 00:00:00+00:00,14.05
+2020-04-30 01:00:00+00:00,13.64
+2020-04-30 02:00:00+00:00,13.84
+2020-04-30 03:00:00+00:00,17.4
+2020-04-30 04:00:00+00:00,21.35
+2020-04-30 05:00:00+00:00,24.97
+2020-04-30 06:00:00+00:00,25.11
+2020-04-30 07:00:00+00:00,23.46
+2020-04-30 08:00:00+00:00,21.89
+2020-04-30 09:00:00+00:00,21.02
+2020-04-30 10:00:00+00:00,14.81
+2020-04-30 11:00:00+00:00,9.25
+2020-04-30 12:00:00+00:00,10.22
+2020-04-30 13:00:00+00:00,13.45
+2020-04-30 14:00:00+00:00,17.75
+2020-04-30 15:00:00+00:00,23.41
+2020-04-30 16:00:00+00:00,27.13
+2020-04-30 17:00:00+00:00,34.74
+2020-04-30 18:00:00+00:00,34.66
+2020-04-30 19:00:00+00:00,29.02
+2020-04-30 20:00:00+00:00,22.04
+2020-04-30 21:00:00+00:00,13.77
+2020-04-30 22:00:00+00:00,5.5
+2020-04-30 23:00:00+00:00,5.35
+2020-05-01 00:00:00+00:00,3.82
+2020-05-01 01:00:00+00:00,2.63
+2020-05-01 02:00:00+00:00,1.56
+2020-05-01 03:00:00+00:00,2.46
+2020-05-01 04:00:00+00:00,2.54
+2020-05-01 05:00:00+00:00,1.5
+2020-05-01 06:00:00+00:00,-1.57
+2020-05-01 07:00:00+00:00,-2.43
+2020-05-01 08:00:00+00:00,-2.89
+2020-05-01 09:00:00+00:00,-2.47
+2020-05-01 10:00:00+00:00,0.35
+2020-05-01 11:00:00+00:00,-2.04
+2020-05-01 12:00:00+00:00,-2.06
+2020-05-01 13:00:00+00:00,-0.04
+2020-05-01 14:00:00+00:00,1.95
+2020-05-01 15:00:00+00:00,7.88
+2020-05-01 16:00:00+00:00,18.99
+2020-05-01 17:00:00+00:00,23.5
+2020-05-01 18:00:00+00:00,28.43
+2020-05-01 19:00:00+00:00,26.88
+2020-05-01 20:00:00+00:00,20.91
+2020-05-01 21:00:00+00:00,16.0
+2020-05-01 22:00:00+00:00,12.2
+2020-05-01 23:00:00+00:00,10.0
+2020-05-02 00:00:00+00:00,10.0
+2020-05-02 01:00:00+00:00,8.0
+2020-05-02 02:00:00+00:00,8.0
+2020-05-02 03:00:00+00:00,8.0
+2020-05-02 04:00:00+00:00,7.2
+2020-05-02 05:00:00+00:00,8.0
+2020-05-02 06:00:00+00:00,10.3
+2020-05-02 07:00:00+00:00,10.55
+2020-05-02 08:00:00+00:00,10.7
+2020-05-02 09:00:00+00:00,11.28
+2020-05-02 10:00:00+00:00,10.01
+2020-05-02 11:00:00+00:00,7.35
+2020-05-02 12:00:00+00:00,5.65
+2020-05-02 13:00:00+00:00,5.25
+2020-05-02 14:00:00+00:00,5.66
+2020-05-02 15:00:00+00:00,8.5
+2020-05-02 16:00:00+00:00,17.93
+2020-05-02 17:00:00+00:00,25.51
+2020-05-02 18:00:00+00:00,28.04
+2020-05-02 19:00:00+00:00,26.37
+2020-05-02 20:00:00+00:00,24.38
+2020-05-02 21:00:00+00:00,20.49
+2020-05-02 22:00:00+00:00,18.0
+2020-05-02 23:00:00+00:00,13.76
+2020-05-03 00:00:00+00:00,11.44
+2020-05-03 01:00:00+00:00,11.15
+2020-05-03 02:00:00+00:00,11.82
+2020-05-03 03:00:00+00:00,13.37
+2020-05-03 04:00:00+00:00,11.56
+2020-05-03 05:00:00+00:00,10.94
+2020-05-03 06:00:00+00:00,10.0
+2020-05-03 07:00:00+00:00,9.4
+2020-05-03 08:00:00+00:00,9.7
+2020-05-03 09:00:00+00:00,10.0
+2020-05-03 10:00:00+00:00,10.0
+2020-05-03 11:00:00+00:00,7.06
+2020-05-03 12:00:00+00:00,5.84
+2020-05-03 13:00:00+00:00,5.57
+2020-05-03 14:00:00+00:00,7.14
+2020-05-03 15:00:00+00:00,10.21
+2020-05-03 16:00:00+00:00,20.05
+2020-05-03 17:00:00+00:00,24.97
+2020-05-03 18:00:00+00:00,28.69
+2020-05-03 19:00:00+00:00,28.96
+2020-05-03 20:00:00+00:00,25.37
+2020-05-03 21:00:00+00:00,22.33
+2020-05-03 22:00:00+00:00,22.2
+2020-05-03 23:00:00+00:00,20.46
+2020-05-04 00:00:00+00:00,21.86
+2020-05-04 01:00:00+00:00,20.7
+2020-05-04 02:00:00+00:00,20.14
+2020-05-04 03:00:00+00:00,22.99
+2020-05-04 04:00:00+00:00,34.05
+2020-05-04 05:00:00+00:00,48.53
+2020-05-04 06:00:00+00:00,55.13
+2020-05-04 07:00:00+00:00,40.04
+2020-05-04 08:00:00+00:00,27.86
+2020-05-04 09:00:00+00:00,25.07
+2020-05-04 10:00:00+00:00,22.96
+2020-05-04 11:00:00+00:00,20.74
+2020-05-04 12:00:00+00:00,19.02
+2020-05-04 13:00:00+00:00,19.58
+2020-05-04 14:00:00+00:00,19.81
+2020-05-04 15:00:00+00:00,22.39
+2020-05-04 16:00:00+00:00,24.24
+2020-05-04 17:00:00+00:00,27.92
+2020-05-04 18:00:00+00:00,28.97
+2020-05-04 19:00:00+00:00,25.99
+2020-05-04 20:00:00+00:00,22.51
+2020-05-04 21:00:00+00:00,19.89
+2020-05-04 22:00:00+00:00,18.14
+2020-05-04 23:00:00+00:00,17.99
+2020-05-05 00:00:00+00:00,17.2
+2020-05-05 01:00:00+00:00,18.05
+2020-05-05 02:00:00+00:00,18.07
+2020-05-05 03:00:00+00:00,20.08
+2020-05-05 04:00:00+00:00,23.2
+2020-05-05 05:00:00+00:00,27.61
+2020-05-05 06:00:00+00:00,26.06
+2020-05-05 07:00:00+00:00,22.35
+2020-05-05 08:00:00+00:00,19.92
+2020-05-05 09:00:00+00:00,21.02
+2020-05-05 10:00:00+00:00,20.27
+2020-05-05 11:00:00+00:00,19.1
+2020-05-05 12:00:00+00:00,17.16
+2020-05-05 13:00:00+00:00,16.12
+2020-05-05 14:00:00+00:00,17.31
+2020-05-05 15:00:00+00:00,20.42
+2020-05-05 16:00:00+00:00,24.1
+2020-05-05 17:00:00+00:00,28.75
+2020-05-05 18:00:00+00:00,32.41
+2020-05-05 19:00:00+00:00,27.34
+2020-05-05 20:00:00+00:00,25.34
+2020-05-05 21:00:00+00:00,23.24
+2020-05-05 22:00:00+00:00,20.99
+2020-05-05 23:00:00+00:00,20.06
+2020-05-06 00:00:00+00:00,20.0
+2020-05-06 01:00:00+00:00,19.04
+2020-05-06 02:00:00+00:00,17.04
+2020-05-06 03:00:00+00:00,20.1
+2020-05-06 04:00:00+00:00,24.95
+2020-05-06 05:00:00+00:00,29.2
+2020-05-06 06:00:00+00:00,26.96
+2020-05-06 07:00:00+00:00,24.22
+2020-05-06 08:00:00+00:00,21.16
+2020-05-06 09:00:00+00:00,20.34
+2020-05-06 10:00:00+00:00,20.28
+2020-05-06 11:00:00+00:00,18.07
+2020-05-06 12:00:00+00:00,16.41
+2020-05-06 13:00:00+00:00,16.27
+2020-05-06 14:00:00+00:00,16.69
+2020-05-06 15:00:00+00:00,18.79
+2020-05-06 16:00:00+00:00,22.94
+2020-05-06 17:00:00+00:00,24.96
+2020-05-06 18:00:00+00:00,25.42
+2020-05-06 19:00:00+00:00,24.97
+2020-05-06 20:00:00+00:00,24.68
+2020-05-06 21:00:00+00:00,22.14
+2020-05-06 22:00:00+00:00,20.08
+2020-05-06 23:00:00+00:00,19.03
+2020-05-07 00:00:00+00:00,18.57
+2020-05-07 01:00:00+00:00,18.5
+2020-05-07 02:00:00+00:00,18.48
+2020-05-07 03:00:00+00:00,19.07
+2020-05-07 04:00:00+00:00,23.01
+2020-05-07 05:00:00+00:00,25.03
+2020-05-07 06:00:00+00:00,24.98
+2020-05-07 07:00:00+00:00,21.54
+2020-05-07 08:00:00+00:00,19.7
+2020-05-07 09:00:00+00:00,19.06
+2020-05-07 10:00:00+00:00,17.06
+2020-05-07 11:00:00+00:00,16.75
+2020-05-07 12:00:00+00:00,17.34
+2020-05-07 13:00:00+00:00,18.32
+2020-05-07 14:00:00+00:00,19.0
+2020-05-07 15:00:00+00:00,20.39
+2020-05-07 16:00:00+00:00,26.91
+2020-05-07 17:00:00+00:00,48.95
+2020-05-07 18:00:00+00:00,50.98
+2020-05-07 19:00:00+00:00,35.45
+2020-05-07 20:00:00+00:00,27.93
+2020-05-07 21:00:00+00:00,25.8
+2020-05-07 22:00:00+00:00,23.18
+2020-05-07 23:00:00+00:00,20.44
+2020-05-08 00:00:00+00:00,20.04
+2020-05-08 01:00:00+00:00,20.09
+2020-05-08 02:00:00+00:00,20.83
+2020-05-08 03:00:00+00:00,22.61
+2020-05-08 04:00:00+00:00,26.95
+2020-05-08 05:00:00+00:00,30.09
+2020-05-08 06:00:00+00:00,26.8
+2020-05-08 07:00:00+00:00,22.99
+2020-05-08 08:00:00+00:00,20.35
+2020-05-08 09:00:00+00:00,19.01
+2020-05-08 10:00:00+00:00,17.89
+2020-05-08 11:00:00+00:00,16.0
+2020-05-08 12:00:00+00:00,15.04
+2020-05-08 13:00:00+00:00,16.26
+2020-05-08 14:00:00+00:00,19.3
+2020-05-08 15:00:00+00:00,22.47
+2020-05-08 16:00:00+00:00,26.96
+2020-05-08 17:00:00+00:00,36.93
+2020-05-08 18:00:00+00:00,41.62
+2020-05-08 19:00:00+00:00,30.71
+2020-05-08 20:00:00+00:00,29.33
+2020-05-08 21:00:00+00:00,24.9
+2020-05-08 22:00:00+00:00,21.51
+2020-05-08 23:00:00+00:00,20.72
+2020-05-09 00:00:00+00:00,20.89
+2020-05-09 01:00:00+00:00,21.01
+2020-05-09 02:00:00+00:00,22.0
+2020-05-09 03:00:00+00:00,21.73
+2020-05-09 04:00:00+00:00,21.11
+2020-05-09 05:00:00+00:00,21.11
+2020-05-09 06:00:00+00:00,21.06
+2020-05-09 07:00:00+00:00,20.24
+2020-05-09 08:00:00+00:00,18.79
+2020-05-09 09:00:00+00:00,19.01
+2020-05-09 10:00:00+00:00,18.38
+2020-05-09 11:00:00+00:00,16.93
+2020-05-09 12:00:00+00:00,16.02
+2020-05-09 13:00:00+00:00,14.75
+2020-05-09 14:00:00+00:00,16.05
+2020-05-09 15:00:00+00:00,21.11
+2020-05-09 16:00:00+00:00,26.97
+2020-05-09 17:00:00+00:00,36.61
+2020-05-09 18:00:00+00:00,33.99
+2020-05-09 19:00:00+00:00,28.28
+2020-05-09 20:00:00+00:00,26.41
+2020-05-09 21:00:00+00:00,22.93
+2020-05-09 22:00:00+00:00,20.7
+2020-05-09 23:00:00+00:00,19.41
+2020-05-10 00:00:00+00:00,19.1
+2020-05-10 01:00:00+00:00,18.29
+2020-05-10 02:00:00+00:00,16.43
+2020-05-10 03:00:00+00:00,16.0
+2020-05-10 04:00:00+00:00,15.0
+2020-05-10 05:00:00+00:00,12.76
+2020-05-10 06:00:00+00:00,14.01
+2020-05-10 07:00:00+00:00,13.77
+2020-05-10 08:00:00+00:00,12.64
+2020-05-10 09:00:00+00:00,12.46
+2020-05-10 10:00:00+00:00,11.72
+2020-05-10 11:00:00+00:00,6.0
+2020-05-10 12:00:00+00:00,2.36
+2020-05-10 13:00:00+00:00,0.93
+2020-05-10 14:00:00+00:00,2.97
+2020-05-10 15:00:00+00:00,6.23
+2020-05-10 16:00:00+00:00,12.1
+2020-05-10 17:00:00+00:00,14.51
+2020-05-10 18:00:00+00:00,14.73
+2020-05-10 19:00:00+00:00,14.99
+2020-05-10 20:00:00+00:00,14.7
+2020-05-10 21:00:00+00:00,10.1
+2020-05-10 22:00:00+00:00,5.79
+2020-05-10 23:00:00+00:00,2.02
+2020-05-11 00:00:00+00:00,0.13
+2020-05-11 01:00:00+00:00,-0.01
+2020-05-11 02:00:00+00:00,0.02
+2020-05-11 03:00:00+00:00,3.74
+2020-05-11 04:00:00+00:00,18.96
+2020-05-11 05:00:00+00:00,22.66
+2020-05-11 06:00:00+00:00,24.95
+2020-05-11 07:00:00+00:00,22.5
+2020-05-11 08:00:00+00:00,20.14
+2020-05-11 09:00:00+00:00,19.07
+2020-05-11 10:00:00+00:00,16.46
+2020-05-11 11:00:00+00:00,14.15
+2020-05-11 12:00:00+00:00,8.71
+2020-05-11 13:00:00+00:00,8.01
+2020-05-11 14:00:00+00:00,8.07
+2020-05-11 15:00:00+00:00,13.89
+2020-05-11 16:00:00+00:00,18.33
+2020-05-11 17:00:00+00:00,22.0
+2020-05-11 18:00:00+00:00,22.24
+2020-05-11 19:00:00+00:00,23.97
+2020-05-11 20:00:00+00:00,21.85
+2020-05-11 21:00:00+00:00,20.01
+2020-05-11 22:00:00+00:00,21.4
+2020-05-11 23:00:00+00:00,18.93
+2020-05-12 00:00:00+00:00,18.06
+2020-05-12 01:00:00+00:00,17.05
+2020-05-12 02:00:00+00:00,16.84
+2020-05-12 03:00:00+00:00,19.3
+2020-05-12 04:00:00+00:00,26.53
+2020-05-12 05:00:00+00:00,33.36
+2020-05-12 06:00:00+00:00,26.68
+2020-05-12 07:00:00+00:00,24.0
+2020-05-12 08:00:00+00:00,22.54
+2020-05-12 09:00:00+00:00,22.0
+2020-05-12 10:00:00+00:00,20.0
+2020-05-12 11:00:00+00:00,18.03
+2020-05-12 12:00:00+00:00,17.03
+2020-05-12 13:00:00+00:00,17.05
+2020-05-12 14:00:00+00:00,17.1
+2020-05-12 15:00:00+00:00,21.53
+2020-05-12 16:00:00+00:00,25.28
+2020-05-12 17:00:00+00:00,27.83
+2020-05-12 18:00:00+00:00,28.76
+2020-05-12 19:00:00+00:00,26.52
+2020-05-12 20:00:00+00:00,25.15
+2020-05-12 21:00:00+00:00,23.6
+2020-05-12 22:00:00+00:00,23.92
+2020-05-12 23:00:00+00:00,22.05
+2020-05-13 00:00:00+00:00,20.46
+2020-05-13 01:00:00+00:00,19.97
+2020-05-13 02:00:00+00:00,20.16
+2020-05-13 03:00:00+00:00,22.58
+2020-05-13 04:00:00+00:00,32.09
+2020-05-13 05:00:00+00:00,43.68
+2020-05-13 06:00:00+00:00,43.09
+2020-05-13 07:00:00+00:00,35.8
+2020-05-13 08:00:00+00:00,35.79
+2020-05-13 09:00:00+00:00,34.0
+2020-05-13 10:00:00+00:00,32.44
+2020-05-13 11:00:00+00:00,30.49
+2020-05-13 12:00:00+00:00,28.8
+2020-05-13 13:00:00+00:00,28.72
+2020-05-13 14:00:00+00:00,28.33
+2020-05-13 15:00:00+00:00,34.88
+2020-05-13 16:00:00+00:00,34.73
+2020-05-13 17:00:00+00:00,34.88
+2020-05-13 18:00:00+00:00,33.5
+2020-05-13 19:00:00+00:00,29.87
+2020-05-13 20:00:00+00:00,23.91
+2020-05-13 21:00:00+00:00,20.06
+2020-05-13 22:00:00+00:00,18.15
+2020-05-13 23:00:00+00:00,17.91
+2020-05-14 00:00:00+00:00,16.75
+2020-05-14 01:00:00+00:00,16.96
+2020-05-14 02:00:00+00:00,18.17
+2020-05-14 03:00:00+00:00,19.03
+2020-05-14 04:00:00+00:00,23.33
+2020-05-14 05:00:00+00:00,29.25
+2020-05-14 06:00:00+00:00,29.48
+2020-05-14 07:00:00+00:00,27.44
+2020-05-14 08:00:00+00:00,24.28
+2020-05-14 09:00:00+00:00,23.0
+2020-05-14 10:00:00+00:00,21.32
+2020-05-14 11:00:00+00:00,19.5
+2020-05-14 12:00:00+00:00,19.62
+2020-05-14 13:00:00+00:00,19.3
+2020-05-14 14:00:00+00:00,19.84
+2020-05-14 15:00:00+00:00,23.42
+2020-05-14 16:00:00+00:00,26.9
+2020-05-14 17:00:00+00:00,28.99
+2020-05-14 18:00:00+00:00,30.08
+2020-05-14 19:00:00+00:00,27.06
+2020-05-14 20:00:00+00:00,25.2
+2020-05-14 21:00:00+00:00,21.89
+2020-05-14 22:00:00+00:00,19.05
+2020-05-14 23:00:00+00:00,17.53
+2020-05-15 00:00:00+00:00,17.03
+2020-05-15 01:00:00+00:00,17.07
+2020-05-15 02:00:00+00:00,17.07
+2020-05-15 03:00:00+00:00,19.71
+2020-05-15 04:00:00+00:00,24.08
+2020-05-15 05:00:00+00:00,27.39
+2020-05-15 06:00:00+00:00,27.97
+2020-05-15 07:00:00+00:00,23.0
+2020-05-15 08:00:00+00:00,22.65
+2020-05-15 09:00:00+00:00,21.6
+2020-05-15 10:00:00+00:00,19.96
+2020-05-15 11:00:00+00:00,18.63
+2020-05-15 12:00:00+00:00,18.45
+2020-05-15 13:00:00+00:00,18.0
+2020-05-15 14:00:00+00:00,18.0
+2020-05-15 15:00:00+00:00,19.99
+2020-05-15 16:00:00+00:00,22.05
+2020-05-15 17:00:00+00:00,24.92
+2020-05-15 18:00:00+00:00,25.9
+2020-05-15 19:00:00+00:00,25.25
+2020-05-15 20:00:00+00:00,21.85
+2020-05-15 21:00:00+00:00,18.86
+2020-05-15 22:00:00+00:00,20.0
+2020-05-15 23:00:00+00:00,18.14
+2020-05-16 00:00:00+00:00,17.08
+2020-05-16 01:00:00+00:00,16.43
+2020-05-16 02:00:00+00:00,14.95
+2020-05-16 03:00:00+00:00,14.54
+2020-05-16 04:00:00+00:00,14.94
+2020-05-16 05:00:00+00:00,16.0
+2020-05-16 06:00:00+00:00,15.71
+2020-05-16 07:00:00+00:00,13.39
+2020-05-16 08:00:00+00:00,10.08
+2020-05-16 09:00:00+00:00,10.85
+2020-05-16 10:00:00+00:00,13.27
+2020-05-16 11:00:00+00:00,11.86
+2020-05-16 12:00:00+00:00,8.87
+2020-05-16 13:00:00+00:00,11.24
+2020-05-16 14:00:00+00:00,11.03
+2020-05-16 15:00:00+00:00,14.5
+2020-05-16 16:00:00+00:00,20.39
+2020-05-16 17:00:00+00:00,26.09
+2020-05-16 18:00:00+00:00,28.58
+2020-05-16 19:00:00+00:00,29.42
+2020-05-16 20:00:00+00:00,26.5
+2020-05-16 21:00:00+00:00,23.08
+2020-05-16 22:00:00+00:00,18.93
+2020-05-16 23:00:00+00:00,17.79
+2020-05-17 00:00:00+00:00,15.15
+2020-05-17 01:00:00+00:00,13.66
+2020-05-17 02:00:00+00:00,11.89
+2020-05-17 03:00:00+00:00,12.62
+2020-05-17 04:00:00+00:00,8.52
+2020-05-17 05:00:00+00:00,11.9
+2020-05-17 06:00:00+00:00,11.61
+2020-05-17 07:00:00+00:00,8.08
+2020-05-17 08:00:00+00:00,1.97
+2020-05-17 09:00:00+00:00,0.08
+2020-05-17 10:00:00+00:00,0.96
+2020-05-17 11:00:00+00:00,-5.19
+2020-05-17 12:00:00+00:00,-16.76
+2020-05-17 13:00:00+00:00,-14.9
+2020-05-17 14:00:00+00:00,-2.06
+2020-05-17 15:00:00+00:00,6.41
+2020-05-17 16:00:00+00:00,16.05
+2020-05-17 17:00:00+00:00,20.51
+2020-05-17 18:00:00+00:00,22.18
+2020-05-17 19:00:00+00:00,23.95
+2020-05-17 20:00:00+00:00,23.22
+2020-05-17 21:00:00+00:00,20.54
+2020-05-17 22:00:00+00:00,18.0
+2020-05-17 23:00:00+00:00,15.54
+2020-05-18 00:00:00+00:00,14.01
+2020-05-18 01:00:00+00:00,12.95
+2020-05-18 02:00:00+00:00,13.97
+2020-05-18 03:00:00+00:00,17.98
+2020-05-18 04:00:00+00:00,24.96
+2020-05-18 05:00:00+00:00,27.94
+2020-05-18 06:00:00+00:00,29.91
+2020-05-18 07:00:00+00:00,22.96
+2020-05-18 08:00:00+00:00,18.91
+2020-05-18 09:00:00+00:00,16.9
+2020-05-18 10:00:00+00:00,15.36
+2020-05-18 11:00:00+00:00,14.04
+2020-05-18 12:00:00+00:00,13.26
+2020-05-18 13:00:00+00:00,12.85
+2020-05-18 14:00:00+00:00,13.44
+2020-05-18 15:00:00+00:00,19.07
+2020-05-18 16:00:00+00:00,22.81
+2020-05-18 17:00:00+00:00,25.95
+2020-05-18 18:00:00+00:00,31.9
+2020-05-18 19:00:00+00:00,26.08
+2020-05-18 20:00:00+00:00,23.99
+2020-05-18 21:00:00+00:00,21.04
+2020-05-18 22:00:00+00:00,17.05
+2020-05-18 23:00:00+00:00,16.13
+2020-05-19 00:00:00+00:00,16.16
+2020-05-19 01:00:00+00:00,15.74
+2020-05-19 02:00:00+00:00,17.01
+2020-05-19 03:00:00+00:00,18.53
+2020-05-19 04:00:00+00:00,22.26
+2020-05-19 05:00:00+00:00,26.04
+2020-05-19 06:00:00+00:00,28.18
+2020-05-19 07:00:00+00:00,22.96
+2020-05-19 08:00:00+00:00,20.07
+2020-05-19 09:00:00+00:00,20.13
+2020-05-19 10:00:00+00:00,19.31
+2020-05-19 11:00:00+00:00,18.19
+2020-05-19 12:00:00+00:00,17.71
+2020-05-19 13:00:00+00:00,17.82
+2020-05-19 14:00:00+00:00,19.03
+2020-05-19 15:00:00+00:00,22.14
+2020-05-19 16:00:00+00:00,28.67
+2020-05-19 17:00:00+00:00,42.65
+2020-05-19 18:00:00+00:00,49.98
+2020-05-19 19:00:00+00:00,40.48
+2020-05-19 20:00:00+00:00,29.07
+2020-05-19 21:00:00+00:00,23.18
+2020-05-19 22:00:00+00:00,21.24
+2020-05-19 23:00:00+00:00,22.35
+2020-05-20 00:00:00+00:00,21.58
+2020-05-20 01:00:00+00:00,21.56
+2020-05-20 02:00:00+00:00,20.67
+2020-05-20 03:00:00+00:00,23.25
+2020-05-20 04:00:00+00:00,44.83
+2020-05-20 05:00:00+00:00,56.69
+2020-05-20 06:00:00+00:00,57.0
+2020-05-20 07:00:00+00:00,34.31
+2020-05-20 08:00:00+00:00,28.72
+2020-05-20 09:00:00+00:00,30.55
+2020-05-20 10:00:00+00:00,28.09
+2020-05-20 11:00:00+00:00,23.43
+2020-05-20 12:00:00+00:00,22.93
+2020-05-20 13:00:00+00:00,23.06
+2020-05-20 14:00:00+00:00,23.24
+2020-05-20 15:00:00+00:00,25.63
+2020-05-20 16:00:00+00:00,33.97
+2020-05-20 17:00:00+00:00,44.58
+2020-05-20 18:00:00+00:00,56.3
+2020-05-20 19:00:00+00:00,46.9
+2020-05-20 20:00:00+00:00,35.42
+2020-05-20 21:00:00+00:00,22.94
+2020-05-20 22:00:00+00:00,21.37
+2020-05-20 23:00:00+00:00,20.01
+2020-05-21 00:00:00+00:00,17.29
+2020-05-21 01:00:00+00:00,16.74
+2020-05-21 02:00:00+00:00,16.84
+2020-05-21 03:00:00+00:00,16.18
+2020-05-21 04:00:00+00:00,17.85
+2020-05-21 05:00:00+00:00,19.77
+2020-05-21 06:00:00+00:00,19.56
+2020-05-21 07:00:00+00:00,16.12
+2020-05-21 08:00:00+00:00,14.82
+2020-05-21 09:00:00+00:00,14.92
+2020-05-21 10:00:00+00:00,14.81
+2020-05-21 11:00:00+00:00,13.29
+2020-05-21 12:00:00+00:00,12.14
+2020-05-21 13:00:00+00:00,13.9
+2020-05-21 14:00:00+00:00,15.47
+2020-05-21 15:00:00+00:00,18.0
+2020-05-21 16:00:00+00:00,22.09
+2020-05-21 17:00:00+00:00,29.66
+2020-05-21 18:00:00+00:00,42.66
+2020-05-21 19:00:00+00:00,29.52
+2020-05-21 20:00:00+00:00,24.12
+2020-05-21 21:00:00+00:00,22.78
+2020-05-21 22:00:00+00:00,20.0
+2020-05-21 23:00:00+00:00,17.03
+2020-05-22 00:00:00+00:00,15.5
+2020-05-22 01:00:00+00:00,14.02
+2020-05-22 02:00:00+00:00,14.15
+2020-05-22 03:00:00+00:00,15.75
+2020-05-22 04:00:00+00:00,20.83
+2020-05-22 05:00:00+00:00,21.94
+2020-05-22 06:00:00+00:00,21.92
+2020-05-22 07:00:00+00:00,21.2
+2020-05-22 08:00:00+00:00,16.49
+2020-05-22 09:00:00+00:00,14.59
+2020-05-22 10:00:00+00:00,14.69
+2020-05-22 11:00:00+00:00,14.57
+2020-05-22 12:00:00+00:00,16.09
+2020-05-22 13:00:00+00:00,17.27
+2020-05-22 14:00:00+00:00,18.35
+2020-05-22 15:00:00+00:00,22.07
+2020-05-22 16:00:00+00:00,22.98
+2020-05-22 17:00:00+00:00,23.71
+2020-05-22 18:00:00+00:00,23.35
+2020-05-22 19:00:00+00:00,22.2
+2020-05-22 20:00:00+00:00,22.81
+2020-05-22 21:00:00+00:00,20.47
+2020-05-22 22:00:00+00:00,14.01
+2020-05-22 23:00:00+00:00,11.48
+2020-05-23 00:00:00+00:00,10.87
+2020-05-23 01:00:00+00:00,8.72
+2020-05-23 02:00:00+00:00,9.37
+2020-05-23 03:00:00+00:00,9.5
+2020-05-23 04:00:00+00:00,12.37
+2020-05-23 05:00:00+00:00,15.07
+2020-05-23 06:00:00+00:00,16.57
+2020-05-23 07:00:00+00:00,16.72
+2020-05-23 08:00:00+00:00,15.53
+2020-05-23 09:00:00+00:00,12.63
+2020-05-23 10:00:00+00:00,12.7
+2020-05-23 11:00:00+00:00,4.64
+2020-05-23 12:00:00+00:00,0.01
+2020-05-23 13:00:00+00:00,-0.94
+2020-05-23 14:00:00+00:00,-0.38
+2020-05-23 15:00:00+00:00,0.75
+2020-05-23 16:00:00+00:00,8.01
+2020-05-23 17:00:00+00:00,12.2
+2020-05-23 18:00:00+00:00,14.04
+2020-05-23 19:00:00+00:00,13.94
+2020-05-23 20:00:00+00:00,14.56
+2020-05-23 21:00:00+00:00,13.99
+2020-05-23 22:00:00+00:00,0.03
+2020-05-23 23:00:00+00:00,-2.44
+2020-05-24 00:00:00+00:00,-8.77
+2020-05-24 01:00:00+00:00,-20.01
+2020-05-24 02:00:00+00:00,-20.37
+2020-05-24 03:00:00+00:00,-24.65
+2020-05-24 04:00:00+00:00,-30.98
+2020-05-24 05:00:00+00:00,-25.0
+2020-05-24 06:00:00+00:00,-26.97
+2020-05-24 07:00:00+00:00,-39.46
+2020-05-24 08:00:00+00:00,-63.04
+2020-05-24 09:00:00+00:00,-63.06
+2020-05-24 10:00:00+00:00,-70.04
+2020-05-24 11:00:00+00:00,-74.97
+2020-05-24 12:00:00+00:00,-74.97
+2020-05-24 13:00:00+00:00,-69.99
+2020-05-24 14:00:00+00:00,-57.74
+2020-05-24 15:00:00+00:00,-16.98
+2020-05-24 16:00:00+00:00,1.54
+2020-05-24 17:00:00+00:00,8.03
+2020-05-24 18:00:00+00:00,14.0
+2020-05-24 19:00:00+00:00,14.39
+2020-05-24 20:00:00+00:00,16.31
+2020-05-24 21:00:00+00:00,8.0
+2020-05-24 22:00:00+00:00,13.01
+2020-05-24 23:00:00+00:00,12.03
+2020-05-25 00:00:00+00:00,8.03
+2020-05-25 01:00:00+00:00,7.59
+2020-05-25 02:00:00+00:00,7.73
+2020-05-25 03:00:00+00:00,9.99
+2020-05-25 04:00:00+00:00,16.02
+2020-05-25 05:00:00+00:00,21.09
+2020-05-25 06:00:00+00:00,22.06
+2020-05-25 07:00:00+00:00,20.92
+2020-05-25 08:00:00+00:00,20.0
+2020-05-25 09:00:00+00:00,20.94
+2020-05-25 10:00:00+00:00,17.5
+2020-05-25 11:00:00+00:00,15.47
+2020-05-25 12:00:00+00:00,14.38
+2020-05-25 13:00:00+00:00,14.0
+2020-05-25 14:00:00+00:00,15.75
+2020-05-25 15:00:00+00:00,18.9
+2020-05-25 16:00:00+00:00,23.53
+2020-05-25 17:00:00+00:00,26.08
+2020-05-25 18:00:00+00:00,38.32
+2020-05-25 19:00:00+00:00,34.35
+2020-05-25 20:00:00+00:00,26.25
+2020-05-25 21:00:00+00:00,23.19
+2020-05-25 22:00:00+00:00,21.1
+2020-05-25 23:00:00+00:00,22.63
+2020-05-26 00:00:00+00:00,21.41
+2020-05-26 01:00:00+00:00,21.49
+2020-05-26 02:00:00+00:00,22.65
+2020-05-26 03:00:00+00:00,22.72
+2020-05-26 04:00:00+00:00,34.94
+2020-05-26 05:00:00+00:00,40.05
+2020-05-26 06:00:00+00:00,34.65
+2020-05-26 07:00:00+00:00,24.21
+2020-05-26 08:00:00+00:00,22.59
+2020-05-26 09:00:00+00:00,21.97
+2020-05-26 10:00:00+00:00,21.0
+2020-05-26 11:00:00+00:00,19.75
+2020-05-26 12:00:00+00:00,19.98
+2020-05-26 13:00:00+00:00,20.91
+2020-05-26 14:00:00+00:00,21.0
+2020-05-26 15:00:00+00:00,24.2
+2020-05-26 16:00:00+00:00,31.29
+2020-05-26 17:00:00+00:00,47.9
+2020-05-26 18:00:00+00:00,50.15
+2020-05-26 19:00:00+00:00,35.95
+2020-05-26 20:00:00+00:00,31.51
+2020-05-26 21:00:00+00:00,24.15
+2020-05-26 22:00:00+00:00,23.15
+2020-05-26 23:00:00+00:00,21.68
+2020-05-27 00:00:00+00:00,21.4
+2020-05-27 01:00:00+00:00,21.92
+2020-05-27 02:00:00+00:00,21.99
+2020-05-27 03:00:00+00:00,22.54
+2020-05-27 04:00:00+00:00,26.05
+2020-05-27 05:00:00+00:00,31.94
+2020-05-27 06:00:00+00:00,26.85
+2020-05-27 07:00:00+00:00,24.1
+2020-05-27 08:00:00+00:00,21.16
+2020-05-27 09:00:00+00:00,23.08
+2020-05-27 10:00:00+00:00,22.04
+2020-05-27 11:00:00+00:00,20.71
+2020-05-27 12:00:00+00:00,20.0
+2020-05-27 13:00:00+00:00,19.99
+2020-05-27 14:00:00+00:00,19.65
+2020-05-27 15:00:00+00:00,21.4
+2020-05-27 16:00:00+00:00,22.76
+2020-05-27 17:00:00+00:00,24.92
+2020-05-27 18:00:00+00:00,25.54
+2020-05-27 19:00:00+00:00,23.99
+2020-05-27 20:00:00+00:00,22.65
+2020-05-27 21:00:00+00:00,20.02
+2020-05-27 22:00:00+00:00,18.09
+2020-05-27 23:00:00+00:00,16.31
+2020-05-28 00:00:00+00:00,16.2
+2020-05-28 01:00:00+00:00,15.92
+2020-05-28 02:00:00+00:00,16.16
+2020-05-28 03:00:00+00:00,18.03
+2020-05-28 04:00:00+00:00,22.94
+2020-05-28 05:00:00+00:00,25.55
+2020-05-28 06:00:00+00:00,25.16
+2020-05-28 07:00:00+00:00,22.99
+2020-05-28 08:00:00+00:00,20.15
+2020-05-28 09:00:00+00:00,18.95
+2020-05-28 10:00:00+00:00,18.0
+2020-05-28 11:00:00+00:00,17.03
+2020-05-28 12:00:00+00:00,16.9
+2020-05-28 13:00:00+00:00,16.19
+2020-05-28 14:00:00+00:00,15.48
+2020-05-28 15:00:00+00:00,19.99
+2020-05-28 16:00:00+00:00,22.99
+2020-05-28 17:00:00+00:00,26.15
+2020-05-28 18:00:00+00:00,26.11
+2020-05-28 19:00:00+00:00,27.16
+2020-05-28 20:00:00+00:00,25.05
+2020-05-28 21:00:00+00:00,22.39
+2020-05-28 22:00:00+00:00,19.42
+2020-05-28 23:00:00+00:00,18.88
+2020-05-29 00:00:00+00:00,18.22
+2020-05-29 01:00:00+00:00,19.07
+2020-05-29 02:00:00+00:00,19.43
+2020-05-29 03:00:00+00:00,22.36
+2020-05-29 04:00:00+00:00,27.92
+2020-05-29 05:00:00+00:00,37.2
+2020-05-29 06:00:00+00:00,30.92
+2020-05-29 07:00:00+00:00,24.4
+2020-05-29 08:00:00+00:00,22.35
+2020-05-29 09:00:00+00:00,20.68
+2020-05-29 10:00:00+00:00,19.91
+2020-05-29 11:00:00+00:00,19.04
+2020-05-29 12:00:00+00:00,16.15
+2020-05-29 13:00:00+00:00,17.3
+2020-05-29 14:00:00+00:00,18.1
+2020-05-29 15:00:00+00:00,22.85
+2020-05-29 16:00:00+00:00,25.68
+2020-05-29 17:00:00+00:00,26.49
+2020-05-29 18:00:00+00:00,25.79
+2020-05-29 19:00:00+00:00,25.97
+2020-05-29 20:00:00+00:00,24.16
+2020-05-29 21:00:00+00:00,22.32
+2020-05-29 22:00:00+00:00,18.27
+2020-05-29 23:00:00+00:00,15.55
+2020-05-30 00:00:00+00:00,15.06
+2020-05-30 01:00:00+00:00,15.0
+2020-05-30 02:00:00+00:00,14.55
+2020-05-30 03:00:00+00:00,15.0
+2020-05-30 04:00:00+00:00,14.4
+2020-05-30 05:00:00+00:00,15.04
+2020-05-30 06:00:00+00:00,13.0
+2020-05-30 07:00:00+00:00,12.0
+2020-05-30 08:00:00+00:00,9.33
+2020-05-30 09:00:00+00:00,7.17
+2020-05-30 10:00:00+00:00,9.44
+2020-05-30 11:00:00+00:00,4.8
+2020-05-30 12:00:00+00:00,2.61
+2020-05-30 13:00:00+00:00,2.17
+2020-05-30 14:00:00+00:00,4.61
+2020-05-30 15:00:00+00:00,9.06
+2020-05-30 16:00:00+00:00,15.33
+2020-05-30 17:00:00+00:00,17.58
+2020-05-30 18:00:00+00:00,17.46
+2020-05-30 19:00:00+00:00,18.28
+2020-05-30 20:00:00+00:00,17.91
+2020-05-30 21:00:00+00:00,17.26
+2020-05-30 22:00:00+00:00,11.88
+2020-05-30 23:00:00+00:00,11.6
+2020-05-31 00:00:00+00:00,11.76
+2020-05-31 01:00:00+00:00,11.09
+2020-05-31 02:00:00+00:00,8.83
+2020-05-31 03:00:00+00:00,7.15
+2020-05-31 04:00:00+00:00,5.56
+2020-05-31 05:00:00+00:00,6.12
+2020-05-31 06:00:00+00:00,2.58
+2020-05-31 07:00:00+00:00,2.7
+2020-05-31 08:00:00+00:00,0.1
+2020-05-31 09:00:00+00:00,1.05
+2020-05-31 10:00:00+00:00,0.85
+2020-05-31 11:00:00+00:00,-7.68
+2020-05-31 12:00:00+00:00,-35.51
+2020-05-31 13:00:00+00:00,-45.05
+2020-05-31 14:00:00+00:00,-20.22
+2020-05-31 15:00:00+00:00,-0.1
+2020-05-31 16:00:00+00:00,4.98
+2020-05-31 17:00:00+00:00,12.54
+2020-05-31 18:00:00+00:00,12.57
+2020-05-31 19:00:00+00:00,13.38
+2020-05-31 20:00:00+00:00,12.59
+2020-05-31 21:00:00+00:00,11.1
+2020-05-31 22:00:00+00:00,8.15
+2020-05-31 23:00:00+00:00,8.93
+2020-06-01 00:00:00+00:00,9.8
+2020-06-01 01:00:00+00:00,6.07
+2020-06-01 02:00:00+00:00,4.07
+2020-06-01 03:00:00+00:00,5.77
+2020-06-01 04:00:00+00:00,7.31
+2020-06-01 05:00:00+00:00,10.05
+2020-06-01 06:00:00+00:00,10.96
+2020-06-01 07:00:00+00:00,9.17
+2020-06-01 08:00:00+00:00,4.01
+2020-06-01 09:00:00+00:00,1.71
+2020-06-01 10:00:00+00:00,3.04
+2020-06-01 11:00:00+00:00,-20.51
+2020-06-01 12:00:00+00:00,-48.17
+2020-06-01 13:00:00+00:00,-15.47
+2020-06-01 14:00:00+00:00,0.47
+2020-06-01 15:00:00+00:00,11.53
+2020-06-01 16:00:00+00:00,16.57
+2020-06-01 17:00:00+00:00,22.0
+2020-06-01 18:00:00+00:00,23.05
+2020-06-01 19:00:00+00:00,22.91
+2020-06-01 20:00:00+00:00,23.37
+2020-06-01 21:00:00+00:00,20.9
+2020-06-01 22:00:00+00:00,18.08
+2020-06-01 23:00:00+00:00,16.33
+2020-06-02 00:00:00+00:00,14.99
+2020-06-02 01:00:00+00:00,14.65
+2020-06-02 02:00:00+00:00,15.92
+2020-06-02 03:00:00+00:00,19.96
+2020-06-02 04:00:00+00:00,29.37
+2020-06-02 05:00:00+00:00,47.66
+2020-06-02 06:00:00+00:00,42.29
+2020-06-02 07:00:00+00:00,24.1
+2020-06-02 08:00:00+00:00,21.86
+2020-06-02 09:00:00+00:00,21.45
+2020-06-02 10:00:00+00:00,20.91
+2020-06-02 11:00:00+00:00,19.54
+2020-06-02 12:00:00+00:00,19.02
+2020-06-02 13:00:00+00:00,18.06
+2020-06-02 14:00:00+00:00,20.09
+2020-06-02 15:00:00+00:00,26.02
+2020-06-02 16:00:00+00:00,41.7
+2020-06-02 17:00:00+00:00,53.65
+2020-06-02 18:00:00+00:00,60.75
+2020-06-02 19:00:00+00:00,49.95
+2020-06-02 20:00:00+00:00,37.92
+2020-06-02 21:00:00+00:00,25.92
+2020-06-02 22:00:00+00:00,25.54
+2020-06-02 23:00:00+00:00,24.0
+2020-06-03 00:00:00+00:00,22.72
+2020-06-03 01:00:00+00:00,20.87
+2020-06-03 02:00:00+00:00,20.24
+2020-06-03 03:00:00+00:00,21.17
+2020-06-03 04:00:00+00:00,31.82
+2020-06-03 05:00:00+00:00,51.41
+2020-06-03 06:00:00+00:00,36.06
+2020-06-03 07:00:00+00:00,31.07
+2020-06-03 08:00:00+00:00,28.72
+2020-06-03 09:00:00+00:00,28.0
+2020-06-03 10:00:00+00:00,27.23
+2020-06-03 11:00:00+00:00,25.27
+2020-06-03 12:00:00+00:00,25.58
+2020-06-03 13:00:00+00:00,26.04
+2020-06-03 14:00:00+00:00,25.78
+2020-06-03 15:00:00+00:00,26.18
+2020-06-03 16:00:00+00:00,29.68
+2020-06-03 17:00:00+00:00,40.17
+2020-06-03 18:00:00+00:00,40.1
+2020-06-03 19:00:00+00:00,32.6
+2020-06-03 20:00:00+00:00,27.91
+2020-06-03 21:00:00+00:00,23.99
+2020-06-03 22:00:00+00:00,22.17
+2020-06-03 23:00:00+00:00,20.98
+2020-06-04 00:00:00+00:00,19.61
+2020-06-04 01:00:00+00:00,20.15
+2020-06-04 02:00:00+00:00,20.36
+2020-06-04 03:00:00+00:00,23.83
+2020-06-04 04:00:00+00:00,28.13
+2020-06-04 05:00:00+00:00,33.64
+2020-06-04 06:00:00+00:00,43.97
+2020-06-04 07:00:00+00:00,33.25
+2020-06-04 08:00:00+00:00,31.82
+2020-06-04 09:00:00+00:00,31.77
+2020-06-04 10:00:00+00:00,30.5
+2020-06-04 11:00:00+00:00,28.93
+2020-06-04 12:00:00+00:00,26.13
+2020-06-04 13:00:00+00:00,26.0
+2020-06-04 14:00:00+00:00,25.7
+2020-06-04 15:00:00+00:00,26.38
+2020-06-04 16:00:00+00:00,28.2
+2020-06-04 17:00:00+00:00,26.07
+2020-06-04 18:00:00+00:00,25.0
+2020-06-04 19:00:00+00:00,23.94
+2020-06-04 20:00:00+00:00,22.69
+2020-06-04 21:00:00+00:00,18.04
+2020-06-04 22:00:00+00:00,17.25
+2020-06-04 23:00:00+00:00,16.8
+2020-06-05 00:00:00+00:00,17.06
+2020-06-05 01:00:00+00:00,15.99
+2020-06-05 02:00:00+00:00,15.61
+2020-06-05 03:00:00+00:00,17.09
+2020-06-05 04:00:00+00:00,24.41
+2020-06-05 05:00:00+00:00,28.96
+2020-06-05 06:00:00+00:00,37.07
+2020-06-05 07:00:00+00:00,33.07
+2020-06-05 08:00:00+00:00,28.4
+2020-06-05 09:00:00+00:00,31.42
+2020-06-05 10:00:00+00:00,26.43
+2020-06-05 11:00:00+00:00,24.0
+2020-06-05 12:00:00+00:00,22.5
+2020-06-05 13:00:00+00:00,23.02
+2020-06-05 14:00:00+00:00,23.6
+2020-06-05 15:00:00+00:00,25.65
+2020-06-05 16:00:00+00:00,27.91
+2020-06-05 17:00:00+00:00,27.99
+2020-06-05 18:00:00+00:00,27.03
+2020-06-05 19:00:00+00:00,25.89
+2020-06-05 20:00:00+00:00,25.89
+2020-06-05 21:00:00+00:00,20.16
+2020-06-05 22:00:00+00:00,7.69
+2020-06-05 23:00:00+00:00,1.46
+2020-06-06 00:00:00+00:00,-0.09
+2020-06-06 01:00:00+00:00,0.03
+2020-06-06 02:00:00+00:00,1.44
+2020-06-06 03:00:00+00:00,1.35
+2020-06-06 04:00:00+00:00,0.08
+2020-06-06 05:00:00+00:00,2.81
+2020-06-06 06:00:00+00:00,5.79
+2020-06-06 07:00:00+00:00,5.65
+2020-06-06 08:00:00+00:00,4.22
+2020-06-06 09:00:00+00:00,2.42
+2020-06-06 10:00:00+00:00,0.06
+2020-06-06 11:00:00+00:00,-4.9
+2020-06-06 12:00:00+00:00,-3.46
+2020-06-06 13:00:00+00:00,-1.71
+2020-06-06 14:00:00+00:00,0.05
+2020-06-06 15:00:00+00:00,9.78
+2020-06-06 16:00:00+00:00,16.42
+2020-06-06 17:00:00+00:00,21.23
+2020-06-06 18:00:00+00:00,23.27
+2020-06-06 19:00:00+00:00,22.98
+2020-06-06 20:00:00+00:00,23.91
+2020-06-06 21:00:00+00:00,19.96
+2020-06-06 22:00:00+00:00,21.04
+2020-06-06 23:00:00+00:00,17.21
+2020-06-07 00:00:00+00:00,14.93
+2020-06-07 01:00:00+00:00,12.63
+2020-06-07 02:00:00+00:00,10.92
+2020-06-07 03:00:00+00:00,10.96
+2020-06-07 04:00:00+00:00,10.88
+2020-06-07 05:00:00+00:00,14.04
+2020-06-07 06:00:00+00:00,15.36
+2020-06-07 07:00:00+00:00,16.0
+2020-06-07 08:00:00+00:00,15.7
+2020-06-07 09:00:00+00:00,16.06
+2020-06-07 10:00:00+00:00,16.94
+2020-06-07 11:00:00+00:00,13.37
+2020-06-07 12:00:00+00:00,10.76
+2020-06-07 13:00:00+00:00,10.64
+2020-06-07 14:00:00+00:00,13.64
+2020-06-07 15:00:00+00:00,17.0
+2020-06-07 16:00:00+00:00,21.06
+2020-06-07 17:00:00+00:00,25.36
+2020-06-07 18:00:00+00:00,28.56
+2020-06-07 19:00:00+00:00,29.14
+2020-06-07 20:00:00+00:00,32.33
+2020-06-07 21:00:00+00:00,28.91
+2020-06-07 22:00:00+00:00,26.0
+2020-06-07 23:00:00+00:00,22.7
+2020-06-08 00:00:00+00:00,22.01
+2020-06-08 01:00:00+00:00,21.36
+2020-06-08 02:00:00+00:00,21.25
+2020-06-08 03:00:00+00:00,23.03
+2020-06-08 04:00:00+00:00,33.45
+2020-06-08 05:00:00+00:00,41.92
+2020-06-08 06:00:00+00:00,40.25
+2020-06-08 07:00:00+00:00,34.76
+2020-06-08 08:00:00+00:00,33.95
+2020-06-08 09:00:00+00:00,35.0
+2020-06-08 10:00:00+00:00,33.0
+2020-06-08 11:00:00+00:00,31.93
+2020-06-08 12:00:00+00:00,30.2
+2020-06-08 13:00:00+00:00,29.28
+2020-06-08 14:00:00+00:00,29.08
+2020-06-08 15:00:00+00:00,33.31
+2020-06-08 16:00:00+00:00,38.85
+2020-06-08 17:00:00+00:00,38.65
+2020-06-08 18:00:00+00:00,35.23
+2020-06-08 19:00:00+00:00,34.6
+2020-06-08 20:00:00+00:00,33.05
+2020-06-08 21:00:00+00:00,30.0
+2020-06-08 22:00:00+00:00,28.39
+2020-06-08 23:00:00+00:00,25.79
+2020-06-09 00:00:00+00:00,24.08
+2020-06-09 01:00:00+00:00,23.67
+2020-06-09 02:00:00+00:00,23.48
+2020-06-09 03:00:00+00:00,25.27
+2020-06-09 04:00:00+00:00,33.43
+2020-06-09 05:00:00+00:00,43.85
+2020-06-09 06:00:00+00:00,52.31
+2020-06-09 07:00:00+00:00,42.46
+2020-06-09 08:00:00+00:00,46.62
+2020-06-09 09:00:00+00:00,46.68
+2020-06-09 10:00:00+00:00,44.12
+2020-06-09 11:00:00+00:00,39.11
+2020-06-09 12:00:00+00:00,36.39
+2020-06-09 13:00:00+00:00,33.49
+2020-06-09 14:00:00+00:00,33.76
+2020-06-09 15:00:00+00:00,41.61
+2020-06-09 16:00:00+00:00,45.21
+2020-06-09 17:00:00+00:00,48.07
+2020-06-09 18:00:00+00:00,43.09
+2020-06-09 19:00:00+00:00,37.47
+2020-06-09 20:00:00+00:00,32.83
+2020-06-09 21:00:00+00:00,29.06
+2020-06-09 22:00:00+00:00,26.09
+2020-06-09 23:00:00+00:00,24.2
+2020-06-10 00:00:00+00:00,22.61
+2020-06-10 01:00:00+00:00,21.49
+2020-06-10 02:00:00+00:00,22.58
+2020-06-10 03:00:00+00:00,24.15
+2020-06-10 04:00:00+00:00,29.41
+2020-06-10 05:00:00+00:00,35.5
+2020-06-10 06:00:00+00:00,42.15
+2020-06-10 07:00:00+00:00,41.06
+2020-06-10 08:00:00+00:00,40.4
+2020-06-10 09:00:00+00:00,35.81
+2020-06-10 10:00:00+00:00,34.9
+2020-06-10 11:00:00+00:00,34.14
+2020-06-10 12:00:00+00:00,32.4
+2020-06-10 13:00:00+00:00,31.3
+2020-06-10 14:00:00+00:00,30.24
+2020-06-10 15:00:00+00:00,31.87
+2020-06-10 16:00:00+00:00,33.77
+2020-06-10 17:00:00+00:00,34.91
+2020-06-10 18:00:00+00:00,33.05
+2020-06-10 19:00:00+00:00,31.5
+2020-06-10 20:00:00+00:00,31.45
+2020-06-10 21:00:00+00:00,27.77
+2020-06-10 22:00:00+00:00,26.06
+2020-06-10 23:00:00+00:00,22.75
+2020-06-11 00:00:00+00:00,21.07
+2020-06-11 01:00:00+00:00,19.43
+2020-06-11 02:00:00+00:00,18.96
+2020-06-11 03:00:00+00:00,18.96
+2020-06-11 04:00:00+00:00,21.56
+2020-06-11 05:00:00+00:00,26.06
+2020-06-11 06:00:00+00:00,30.0
+2020-06-11 07:00:00+00:00,28.96
+2020-06-11 08:00:00+00:00,26.06
+2020-06-11 09:00:00+00:00,25.51
+2020-06-11 10:00:00+00:00,23.89
+2020-06-11 11:00:00+00:00,21.99
+2020-06-11 12:00:00+00:00,20.5
+2020-06-11 13:00:00+00:00,19.1
+2020-06-11 14:00:00+00:00,19.28
+2020-06-11 15:00:00+00:00,23.07
+2020-06-11 16:00:00+00:00,26.08
+2020-06-11 17:00:00+00:00,30.65
+2020-06-11 18:00:00+00:00,30.17
+2020-06-11 19:00:00+00:00,27.09
+2020-06-11 20:00:00+00:00,26.51
+2020-06-11 21:00:00+00:00,23.81
+2020-06-11 22:00:00+00:00,20.72
+2020-06-11 23:00:00+00:00,17.96
+2020-06-12 00:00:00+00:00,17.09
+2020-06-12 01:00:00+00:00,16.01
+2020-06-12 02:00:00+00:00,16.0
+2020-06-12 03:00:00+00:00,18.08
+2020-06-12 04:00:00+00:00,22.92
+2020-06-12 05:00:00+00:00,25.1
+2020-06-12 06:00:00+00:00,26.01
+2020-06-12 07:00:00+00:00,23.23
+2020-06-12 08:00:00+00:00,21.07
+2020-06-12 09:00:00+00:00,20.5
+2020-06-12 10:00:00+00:00,19.45
+2020-06-12 11:00:00+00:00,15.2
+2020-06-12 12:00:00+00:00,16.19
+2020-06-12 13:00:00+00:00,16.14
+2020-06-12 14:00:00+00:00,17.4
+2020-06-12 15:00:00+00:00,20.06
+2020-06-12 16:00:00+00:00,23.53
+2020-06-12 17:00:00+00:00,27.51
+2020-06-12 18:00:00+00:00,26.22
+2020-06-12 19:00:00+00:00,24.7
+2020-06-12 20:00:00+00:00,25.46
+2020-06-12 21:00:00+00:00,20.78
+2020-06-12 22:00:00+00:00,20.98
+2020-06-12 23:00:00+00:00,19.44
+2020-06-13 00:00:00+00:00,18.7
+2020-06-13 01:00:00+00:00,18.8
+2020-06-13 02:00:00+00:00,19.0
+2020-06-13 03:00:00+00:00,18.9
+2020-06-13 04:00:00+00:00,19.33
+2020-06-13 05:00:00+00:00,19.86
+2020-06-13 06:00:00+00:00,20.0
+2020-06-13 07:00:00+00:00,19.1
+2020-06-13 08:00:00+00:00,18.5
+2020-06-13 09:00:00+00:00,18.11
+2020-06-13 10:00:00+00:00,16.47
+2020-06-13 11:00:00+00:00,16.25
+2020-06-13 12:00:00+00:00,15.89
+2020-06-13 13:00:00+00:00,15.84
+2020-06-13 14:00:00+00:00,17.5
+2020-06-13 15:00:00+00:00,18.5
+2020-06-13 16:00:00+00:00,21.93
+2020-06-13 17:00:00+00:00,24.87
+2020-06-13 18:00:00+00:00,25.96
+2020-06-13 19:00:00+00:00,24.42
+2020-06-13 20:00:00+00:00,24.85
+2020-06-13 21:00:00+00:00,23.06
+2020-06-13 22:00:00+00:00,18.53
+2020-06-13 23:00:00+00:00,16.8
+2020-06-14 00:00:00+00:00,14.91
+2020-06-14 01:00:00+00:00,13.82
+2020-06-14 02:00:00+00:00,14.84
+2020-06-14 03:00:00+00:00,14.04
+2020-06-14 04:00:00+00:00,14.94
+2020-06-14 05:00:00+00:00,15.3
+2020-06-14 06:00:00+00:00,15.0
+2020-06-14 07:00:00+00:00,18.54
+2020-06-14 08:00:00+00:00,19.07
+2020-06-14 09:00:00+00:00,20.74
+2020-06-14 10:00:00+00:00,19.73
+2020-06-14 11:00:00+00:00,17.97
+2020-06-14 12:00:00+00:00,15.14
+2020-06-14 13:00:00+00:00,14.49
+2020-06-14 14:00:00+00:00,14.8
+2020-06-14 15:00:00+00:00,17.7
+2020-06-14 16:00:00+00:00,21.08
+2020-06-14 17:00:00+00:00,23.8
+2020-06-14 18:00:00+00:00,25.97
+2020-06-14 19:00:00+00:00,25.87
+2020-06-14 20:00:00+00:00,27.91
+2020-06-14 21:00:00+00:00,23.17
+2020-06-14 22:00:00+00:00,23.07
+2020-06-14 23:00:00+00:00,20.65
+2020-06-15 00:00:00+00:00,19.06
+2020-06-15 01:00:00+00:00,18.02
+2020-06-15 02:00:00+00:00,17.4
+2020-06-15 03:00:00+00:00,21.36
+2020-06-15 04:00:00+00:00,29.93
+2020-06-15 05:00:00+00:00,35.28
+2020-06-15 06:00:00+00:00,36.05
+2020-06-15 07:00:00+00:00,35.89
+2020-06-15 08:00:00+00:00,34.09
+2020-06-15 09:00:00+00:00,34.0
+2020-06-15 10:00:00+00:00,34.1
+2020-06-15 11:00:00+00:00,33.15
+2020-06-15 12:00:00+00:00,31.9
+2020-06-15 13:00:00+00:00,31.0
+2020-06-15 14:00:00+00:00,30.52
+2020-06-15 15:00:00+00:00,33.0
+2020-06-15 16:00:00+00:00,38.0
+2020-06-15 17:00:00+00:00,43.52
+2020-06-15 18:00:00+00:00,41.07
+2020-06-15 19:00:00+00:00,35.91
+2020-06-15 20:00:00+00:00,36.39
+2020-06-15 21:00:00+00:00,31.92
+2020-06-15 22:00:00+00:00,29.86
+2020-06-15 23:00:00+00:00,26.59
+2020-06-16 00:00:00+00:00,25.17
+2020-06-16 01:00:00+00:00,24.79
+2020-06-16 02:00:00+00:00,24.34
+2020-06-16 03:00:00+00:00,25.1
+2020-06-16 04:00:00+00:00,31.13
+2020-06-16 05:00:00+00:00,38.39
+2020-06-16 06:00:00+00:00,45.9
+2020-06-16 07:00:00+00:00,41.39
+2020-06-16 08:00:00+00:00,39.32
+2020-06-16 09:00:00+00:00,40.31
+2020-06-16 10:00:00+00:00,38.75
+2020-06-16 11:00:00+00:00,34.97
+2020-06-16 12:00:00+00:00,32.21
+2020-06-16 13:00:00+00:00,30.86
+2020-06-16 14:00:00+00:00,30.66
+2020-06-16 15:00:00+00:00,33.73
+2020-06-16 16:00:00+00:00,38.32
+2020-06-16 17:00:00+00:00,42.91
+2020-06-16 18:00:00+00:00,40.66
+2020-06-16 19:00:00+00:00,37.66
+2020-06-16 20:00:00+00:00,34.92
+2020-06-16 21:00:00+00:00,30.94
+2020-06-16 22:00:00+00:00,32.05
+2020-06-16 23:00:00+00:00,30.38
+2020-06-17 00:00:00+00:00,28.1
+2020-06-17 01:00:00+00:00,26.92
+2020-06-17 02:00:00+00:00,26.53
+2020-06-17 03:00:00+00:00,28.76
+2020-06-17 04:00:00+00:00,35.96
+2020-06-17 05:00:00+00:00,51.93
+2020-06-17 06:00:00+00:00,56.52
+2020-06-17 07:00:00+00:00,42.14
+2020-06-17 08:00:00+00:00,38.99
+2020-06-17 09:00:00+00:00,38.39
+2020-06-17 10:00:00+00:00,36.03
+2020-06-17 11:00:00+00:00,36.01
+2020-06-17 12:00:00+00:00,35.05
+2020-06-17 13:00:00+00:00,33.59
+2020-06-17 14:00:00+00:00,33.0
+2020-06-17 15:00:00+00:00,40.06
+2020-06-17 16:00:00+00:00,45.58
+2020-06-17 17:00:00+00:00,47.33
+2020-06-17 18:00:00+00:00,42.32
+2020-06-17 19:00:00+00:00,39.71
+2020-06-17 20:00:00+00:00,36.59
+2020-06-17 21:00:00+00:00,31.7
+2020-06-17 22:00:00+00:00,27.74
+2020-06-17 23:00:00+00:00,25.26
+2020-06-18 00:00:00+00:00,23.51
+2020-06-18 01:00:00+00:00,22.82
+2020-06-18 02:00:00+00:00,22.92
+2020-06-18 03:00:00+00:00,24.31
+2020-06-18 04:00:00+00:00,28.86
+2020-06-18 05:00:00+00:00,34.59
+2020-06-18 06:00:00+00:00,36.59
+2020-06-18 07:00:00+00:00,36.93
+2020-06-18 08:00:00+00:00,36.73
+2020-06-18 09:00:00+00:00,36.87
+2020-06-18 10:00:00+00:00,36.21
+2020-06-18 11:00:00+00:00,34.0
+2020-06-18 12:00:00+00:00,32.17
+2020-06-18 13:00:00+00:00,31.81
+2020-06-18 14:00:00+00:00,30.72
+2020-06-18 15:00:00+00:00,33.1
+2020-06-18 16:00:00+00:00,35.0
+2020-06-18 17:00:00+00:00,36.99
+2020-06-18 18:00:00+00:00,36.3
+2020-06-18 19:00:00+00:00,35.57
+2020-06-18 20:00:00+00:00,34.3
+2020-06-18 21:00:00+00:00,29.98
+2020-06-18 22:00:00+00:00,28.1
+2020-06-18 23:00:00+00:00,24.45
+2020-06-19 00:00:00+00:00,23.25
+2020-06-19 01:00:00+00:00,22.28
+2020-06-19 02:00:00+00:00,22.2
+2020-06-19 03:00:00+00:00,23.07
+2020-06-19 04:00:00+00:00,30.06
+2020-06-19 05:00:00+00:00,35.33
+2020-06-19 06:00:00+00:00,37.8
+2020-06-19 07:00:00+00:00,36.08
+2020-06-19 08:00:00+00:00,34.56
+2020-06-19 09:00:00+00:00,33.33
+2020-06-19 10:00:00+00:00,31.22
+2020-06-19 11:00:00+00:00,28.4
+2020-06-19 12:00:00+00:00,26.89
+2020-06-19 13:00:00+00:00,25.29
+2020-06-19 14:00:00+00:00,24.07
+2020-06-19 15:00:00+00:00,28.64
+2020-06-19 16:00:00+00:00,32.61
+2020-06-19 17:00:00+00:00,34.0
+2020-06-19 18:00:00+00:00,34.22
+2020-06-19 19:00:00+00:00,34.13
+2020-06-19 20:00:00+00:00,35.0
+2020-06-19 21:00:00+00:00,31.5
+2020-06-19 22:00:00+00:00,26.7
+2020-06-19 23:00:00+00:00,24.73
+2020-06-20 00:00:00+00:00,22.8
+2020-06-20 01:00:00+00:00,21.63
+2020-06-20 02:00:00+00:00,20.48
+2020-06-20 03:00:00+00:00,20.04
+2020-06-20 04:00:00+00:00,21.85
+2020-06-20 05:00:00+00:00,22.94
+2020-06-20 06:00:00+00:00,24.17
+2020-06-20 07:00:00+00:00,23.67
+2020-06-20 08:00:00+00:00,22.06
+2020-06-20 09:00:00+00:00,21.5
+2020-06-20 10:00:00+00:00,20.5
+2020-06-20 11:00:00+00:00,17.9
+2020-06-20 12:00:00+00:00,15.27
+2020-06-20 13:00:00+00:00,15.68
+2020-06-20 14:00:00+00:00,18.98
+2020-06-20 15:00:00+00:00,23.67
+2020-06-20 16:00:00+00:00,28.3
+2020-06-20 17:00:00+00:00,30.87
+2020-06-20 18:00:00+00:00,33.0
+2020-06-20 19:00:00+00:00,34.77
+2020-06-20 20:00:00+00:00,34.94
+2020-06-20 21:00:00+00:00,31.58
+2020-06-20 22:00:00+00:00,30.11
+2020-06-20 23:00:00+00:00,25.07
+2020-06-21 00:00:00+00:00,22.15
+2020-06-21 01:00:00+00:00,20.26
+2020-06-21 02:00:00+00:00,16.2
+2020-06-21 03:00:00+00:00,12.53
+2020-06-21 04:00:00+00:00,10.98
+2020-06-21 05:00:00+00:00,11.25
+2020-06-21 06:00:00+00:00,14.0
+2020-06-21 07:00:00+00:00,13.68
+2020-06-21 08:00:00+00:00,15.6
+2020-06-21 09:00:00+00:00,17.0
+2020-06-21 10:00:00+00:00,18.62
+2020-06-21 11:00:00+00:00,13.08
+2020-06-21 12:00:00+00:00,8.26
+2020-06-21 13:00:00+00:00,8.4
+2020-06-21 14:00:00+00:00,11.65
+2020-06-21 15:00:00+00:00,20.84
+2020-06-21 16:00:00+00:00,24.83
+2020-06-21 17:00:00+00:00,29.61
+2020-06-21 18:00:00+00:00,30.2
+2020-06-21 19:00:00+00:00,30.84
+2020-06-21 20:00:00+00:00,32.93
+2020-06-21 21:00:00+00:00,29.9
+2020-06-21 22:00:00+00:00,23.57
+2020-06-21 23:00:00+00:00,21.88
+2020-06-22 00:00:00+00:00,20.61
+2020-06-22 01:00:00+00:00,21.04
+2020-06-22 02:00:00+00:00,21.5
+2020-06-22 03:00:00+00:00,23.04
+2020-06-22 04:00:00+00:00,30.69
+2020-06-22 05:00:00+00:00,35.41
+2020-06-22 06:00:00+00:00,38.58
+2020-06-22 07:00:00+00:00,34.5
+2020-06-22 08:00:00+00:00,33.08
+2020-06-22 09:00:00+00:00,31.66
+2020-06-22 10:00:00+00:00,30.04
+2020-06-22 11:00:00+00:00,24.67
+2020-06-22 12:00:00+00:00,24.49
+2020-06-22 13:00:00+00:00,23.62
+2020-06-22 14:00:00+00:00,24.59
+2020-06-22 15:00:00+00:00,31.41
+2020-06-22 16:00:00+00:00,34.39
+2020-06-22 17:00:00+00:00,36.74
+2020-06-22 18:00:00+00:00,37.63
+2020-06-22 19:00:00+00:00,37.39
+2020-06-22 20:00:00+00:00,36.38
+2020-06-22 21:00:00+00:00,33.01
+2020-06-22 22:00:00+00:00,30.0
+2020-06-22 23:00:00+00:00,27.12
+2020-06-23 00:00:00+00:00,25.88
+2020-06-23 01:00:00+00:00,24.4
+2020-06-23 02:00:00+00:00,24.43
+2020-06-23 03:00:00+00:00,27.04
+2020-06-23 04:00:00+00:00,35.03
+2020-06-23 05:00:00+00:00,37.44
+2020-06-23 06:00:00+00:00,37.16
+2020-06-23 07:00:00+00:00,34.9
+2020-06-23 08:00:00+00:00,31.92
+2020-06-23 09:00:00+00:00,30.24
+2020-06-23 10:00:00+00:00,28.79
+2020-06-23 11:00:00+00:00,28.23
+2020-06-23 12:00:00+00:00,27.82
+2020-06-23 13:00:00+00:00,28.65
+2020-06-23 14:00:00+00:00,30.0
+2020-06-23 15:00:00+00:00,33.0
+2020-06-23 16:00:00+00:00,36.59
+2020-06-23 17:00:00+00:00,44.51
+2020-06-23 18:00:00+00:00,48.65
+2020-06-23 19:00:00+00:00,41.29
+2020-06-23 20:00:00+00:00,38.41
+2020-06-23 21:00:00+00:00,34.3
+2020-06-23 22:00:00+00:00,33.02
+2020-06-23 23:00:00+00:00,31.37
+2020-06-24 00:00:00+00:00,27.83
+2020-06-24 01:00:00+00:00,26.76
+2020-06-24 02:00:00+00:00,26.86
+2020-06-24 03:00:00+00:00,28.53
+2020-06-24 04:00:00+00:00,37.57
+2020-06-24 05:00:00+00:00,41.71
+2020-06-24 06:00:00+00:00,39.03
+2020-06-24 07:00:00+00:00,37.66
+2020-06-24 08:00:00+00:00,36.12
+2020-06-24 09:00:00+00:00,35.21
+2020-06-24 10:00:00+00:00,34.84
+2020-06-24 11:00:00+00:00,33.69
+2020-06-24 12:00:00+00:00,32.77
+2020-06-24 13:00:00+00:00,32.72
+2020-06-24 14:00:00+00:00,33.98
+2020-06-24 15:00:00+00:00,37.16
+2020-06-24 16:00:00+00:00,40.93
+2020-06-24 17:00:00+00:00,47.11
+2020-06-24 18:00:00+00:00,45.65
+2020-06-24 19:00:00+00:00,40.24
+2020-06-24 20:00:00+00:00,38.95
+2020-06-24 21:00:00+00:00,33.98
+2020-06-24 22:00:00+00:00,30.32
+2020-06-24 23:00:00+00:00,27.54
+2020-06-25 00:00:00+00:00,26.51
+2020-06-25 01:00:00+00:00,25.75
+2020-06-25 02:00:00+00:00,25.43
+2020-06-25 03:00:00+00:00,27.1
+2020-06-25 04:00:00+00:00,34.49
+2020-06-25 05:00:00+00:00,40.73
+2020-06-25 06:00:00+00:00,42.09
+2020-06-25 07:00:00+00:00,40.98
+2020-06-25 08:00:00+00:00,38.83
+2020-06-25 09:00:00+00:00,36.5
+2020-06-25 10:00:00+00:00,33.31
+2020-06-25 11:00:00+00:00,31.38
+2020-06-25 12:00:00+00:00,29.94
+2020-06-25 13:00:00+00:00,29.87
+2020-06-25 14:00:00+00:00,32.4
+2020-06-25 15:00:00+00:00,37.06
+2020-06-25 16:00:00+00:00,39.55
+2020-06-25 17:00:00+00:00,44.13
+2020-06-25 18:00:00+00:00,41.23
+2020-06-25 19:00:00+00:00,40.24
+2020-06-25 20:00:00+00:00,38.0
+2020-06-25 21:00:00+00:00,33.43
+2020-06-25 22:00:00+00:00,32.47
+2020-06-25 23:00:00+00:00,28.12
+2020-06-26 00:00:00+00:00,25.96
+2020-06-26 01:00:00+00:00,25.59
+2020-06-26 02:00:00+00:00,25.63
+2020-06-26 03:00:00+00:00,26.8
+2020-06-26 04:00:00+00:00,34.05
+2020-06-26 05:00:00+00:00,38.94
+2020-06-26 06:00:00+00:00,40.13
+2020-06-26 07:00:00+00:00,39.19
+2020-06-26 08:00:00+00:00,36.93
+2020-06-26 09:00:00+00:00,34.64
+2020-06-26 10:00:00+00:00,33.12
+2020-06-26 11:00:00+00:00,32.79
+2020-06-26 12:00:00+00:00,32.42
+2020-06-26 13:00:00+00:00,32.18
+2020-06-26 14:00:00+00:00,33.28
+2020-06-26 15:00:00+00:00,36.45
+2020-06-26 16:00:00+00:00,40.43
+2020-06-26 17:00:00+00:00,46.8
+2020-06-26 18:00:00+00:00,41.96
+2020-06-26 19:00:00+00:00,39.9
+2020-06-26 20:00:00+00:00,40.1
+2020-06-26 21:00:00+00:00,37.4
+2020-06-26 22:00:00+00:00,35.92
+2020-06-26 23:00:00+00:00,30.68
+2020-06-27 00:00:00+00:00,28.3
+2020-06-27 01:00:00+00:00,27.48
+2020-06-27 02:00:00+00:00,27.14
+2020-06-27 03:00:00+00:00,26.82
+2020-06-27 04:00:00+00:00,25.34
+2020-06-27 05:00:00+00:00,27.72
+2020-06-27 06:00:00+00:00,28.44
+2020-06-27 07:00:00+00:00,28.22
+2020-06-27 08:00:00+00:00,27.01
+2020-06-27 09:00:00+00:00,25.0
+2020-06-27 10:00:00+00:00,23.09
+2020-06-27 11:00:00+00:00,21.56
+2020-06-27 12:00:00+00:00,18.29
+2020-06-27 13:00:00+00:00,17.52
+2020-06-27 14:00:00+00:00,18.52
+2020-06-27 15:00:00+00:00,23.05
+2020-06-27 16:00:00+00:00,27.08
+2020-06-27 17:00:00+00:00,30.52
+2020-06-27 18:00:00+00:00,32.28
+2020-06-27 19:00:00+00:00,32.96
+2020-06-27 20:00:00+00:00,32.91
+2020-06-27 21:00:00+00:00,28.09
+2020-06-27 22:00:00+00:00,23.93
+2020-06-27 23:00:00+00:00,21.03
+2020-06-28 00:00:00+00:00,16.9
+2020-06-28 01:00:00+00:00,14.26
+2020-06-28 02:00:00+00:00,15.48
+2020-06-28 03:00:00+00:00,13.02
+2020-06-28 04:00:00+00:00,12.45
+2020-06-28 05:00:00+00:00,12.6
+2020-06-28 06:00:00+00:00,13.36
+2020-06-28 07:00:00+00:00,12.48
+2020-06-28 08:00:00+00:00,14.17
+2020-06-28 09:00:00+00:00,15.9
+2020-06-28 10:00:00+00:00,13.71
+2020-06-28 11:00:00+00:00,1.42
+2020-06-28 12:00:00+00:00,0.08
+2020-06-28 13:00:00+00:00,0.54
+2020-06-28 14:00:00+00:00,2.22
+2020-06-28 15:00:00+00:00,16.9
+2020-06-28 16:00:00+00:00,25.04
+2020-06-28 17:00:00+00:00,29.83
+2020-06-28 18:00:00+00:00,33.04
+2020-06-28 19:00:00+00:00,35.07
+2020-06-28 20:00:00+00:00,36.0
+2020-06-28 21:00:00+00:00,31.14
+2020-06-28 22:00:00+00:00,24.02
+2020-06-28 23:00:00+00:00,19.77
+2020-06-29 00:00:00+00:00,17.76
+2020-06-29 01:00:00+00:00,17.4
+2020-06-29 02:00:00+00:00,17.6
+2020-06-29 03:00:00+00:00,19.88
+2020-06-29 04:00:00+00:00,26.52
+2020-06-29 05:00:00+00:00,35.54
+2020-06-29 06:00:00+00:00,40.45
+2020-06-29 07:00:00+00:00,38.81
+2020-06-29 08:00:00+00:00,35.4
+2020-06-29 09:00:00+00:00,34.03
+2020-06-29 10:00:00+00:00,29.35
+2020-06-29 11:00:00+00:00,22.63
+2020-06-29 12:00:00+00:00,21.98
+2020-06-29 13:00:00+00:00,21.02
+2020-06-29 14:00:00+00:00,19.85
+2020-06-29 15:00:00+00:00,22.84
+2020-06-29 16:00:00+00:00,32.96
+2020-06-29 17:00:00+00:00,34.95
+2020-06-29 18:00:00+00:00,34.9
+2020-06-29 19:00:00+00:00,34.63
+2020-06-29 20:00:00+00:00,33.97
+2020-06-29 21:00:00+00:00,23.28
+2020-06-29 22:00:00+00:00,22.49
+2020-06-29 23:00:00+00:00,21.02
+2020-06-30 00:00:00+00:00,17.53
+2020-06-30 01:00:00+00:00,15.82
+2020-06-30 02:00:00+00:00,16.44
+2020-06-30 03:00:00+00:00,19.1
+2020-06-30 04:00:00+00:00,25.79
+2020-06-30 05:00:00+00:00,31.95
+2020-06-30 06:00:00+00:00,26.14
+2020-06-30 07:00:00+00:00,17.1
+2020-06-30 08:00:00+00:00,2.58
+2020-06-30 09:00:00+00:00,0.39
+2020-06-30 10:00:00+00:00,0.92
+2020-06-30 11:00:00+00:00,-0.08
+2020-06-30 12:00:00+00:00,0.06
+2020-06-30 13:00:00+00:00,1.32
+2020-06-30 14:00:00+00:00,1.44
+2020-06-30 15:00:00+00:00,21.2
+2020-06-30 16:00:00+00:00,27.73
+2020-06-30 17:00:00+00:00,33.38
+2020-06-30 18:00:00+00:00,36.1
+2020-06-30 19:00:00+00:00,35.54
+2020-06-30 20:00:00+00:00,34.94
+2020-06-30 21:00:00+00:00,31.6
+2020-06-30 22:00:00+00:00,23.92
+2020-06-30 23:00:00+00:00,25.04
+2020-07-01 00:00:00+00:00,25.59
+2020-07-01 01:00:00+00:00,25.03
+2020-07-01 02:00:00+00:00,24.78
+2020-07-01 03:00:00+00:00,25.89
+2020-07-01 04:00:00+00:00,33.75
+2020-07-01 05:00:00+00:00,37.97
+2020-07-01 06:00:00+00:00,39.99
+2020-07-01 07:00:00+00:00,38.29
+2020-07-01 08:00:00+00:00,37.06
+2020-07-01 09:00:00+00:00,36.14
+2020-07-01 10:00:00+00:00,28.4
+2020-07-01 11:00:00+00:00,24.16
+2020-07-01 12:00:00+00:00,25.0
+2020-07-01 13:00:00+00:00,26.41
+2020-07-01 14:00:00+00:00,27.17
+2020-07-01 15:00:00+00:00,32.91
+2020-07-01 16:00:00+00:00,37.37
+2020-07-01 17:00:00+00:00,43.29
+2020-07-01 18:00:00+00:00,40.8
+2020-07-01 19:00:00+00:00,40.12
+2020-07-01 20:00:00+00:00,40.25
+2020-07-01 21:00:00+00:00,37.91
+2020-07-01 22:00:00+00:00,34.53
+2020-07-01 23:00:00+00:00,30.91
+2020-07-02 00:00:00+00:00,28.38
+2020-07-02 01:00:00+00:00,27.2
+2020-07-02 02:00:00+00:00,27.9
+2020-07-02 03:00:00+00:00,30.19
+2020-07-02 04:00:00+00:00,38.96
+2020-07-02 05:00:00+00:00,42.84
+2020-07-02 06:00:00+00:00,47.3
+2020-07-02 07:00:00+00:00,41.69
+2020-07-02 08:00:00+00:00,42.14
+2020-07-02 09:00:00+00:00,41.59
+2020-07-02 10:00:00+00:00,39.47
+2020-07-02 11:00:00+00:00,38.33
+2020-07-02 12:00:00+00:00,35.94
+2020-07-02 13:00:00+00:00,35.06
+2020-07-02 14:00:00+00:00,33.92
+2020-07-02 15:00:00+00:00,38.87
+2020-07-02 16:00:00+00:00,46.0
+2020-07-02 17:00:00+00:00,52.65
+2020-07-02 18:00:00+00:00,47.91
+2020-07-02 19:00:00+00:00,45.33
+2020-07-02 20:00:00+00:00,46.0
+2020-07-02 21:00:00+00:00,40.82
+2020-07-02 22:00:00+00:00,40.46
+2020-07-02 23:00:00+00:00,35.0
+2020-07-03 00:00:00+00:00,32.57
+2020-07-03 01:00:00+00:00,31.27
+2020-07-03 02:00:00+00:00,29.9
+2020-07-03 03:00:00+00:00,30.87
+2020-07-03 04:00:00+00:00,39.99
+2020-07-03 05:00:00+00:00,47.1
+2020-07-03 06:00:00+00:00,49.95
+2020-07-03 07:00:00+00:00,43.44
+2020-07-03 08:00:00+00:00,38.95
+2020-07-03 09:00:00+00:00,37.32
+2020-07-03 10:00:00+00:00,34.05
+2020-07-03 11:00:00+00:00,28.88
+2020-07-03 12:00:00+00:00,25.73
+2020-07-03 13:00:00+00:00,24.95
+2020-07-03 14:00:00+00:00,24.22
+2020-07-03 15:00:00+00:00,31.22
+2020-07-03 16:00:00+00:00,37.24
+2020-07-03 17:00:00+00:00,38.82
+2020-07-03 18:00:00+00:00,36.97
+2020-07-03 19:00:00+00:00,35.25
+2020-07-03 20:00:00+00:00,35.02
+2020-07-03 21:00:00+00:00,29.18
+2020-07-03 22:00:00+00:00,27.19
+2020-07-03 23:00:00+00:00,24.28
+2020-07-04 00:00:00+00:00,21.07
+2020-07-04 01:00:00+00:00,14.86
+2020-07-04 02:00:00+00:00,16.15
+2020-07-04 03:00:00+00:00,15.52
+2020-07-04 04:00:00+00:00,14.46
+2020-07-04 05:00:00+00:00,18.56
+2020-07-04 06:00:00+00:00,19.2
+2020-07-04 07:00:00+00:00,2.41
+2020-07-04 08:00:00+00:00,1.47
+2020-07-04 09:00:00+00:00,0.38
+2020-07-04 10:00:00+00:00,0.02
+2020-07-04 11:00:00+00:00,-4.71
+2020-07-04 12:00:00+00:00,0.91
+2020-07-04 13:00:00+00:00,0.29
+2020-07-04 14:00:00+00:00,13.61
+2020-07-04 15:00:00+00:00,21.95
+2020-07-04 16:00:00+00:00,26.81
+2020-07-04 17:00:00+00:00,28.03
+2020-07-04 18:00:00+00:00,27.58
+2020-07-04 19:00:00+00:00,26.73
+2020-07-04 20:00:00+00:00,28.0
+2020-07-04 21:00:00+00:00,24.91
+2020-07-04 22:00:00+00:00,11.21
+2020-07-04 23:00:00+00:00,2.19
+2020-07-05 00:00:00+00:00,0.08
+2020-07-05 01:00:00+00:00,-0.05
+2020-07-05 02:00:00+00:00,-3.82
+2020-07-05 03:00:00+00:00,-13.5
+2020-07-05 04:00:00+00:00,-14.91
+2020-07-05 05:00:00+00:00,-13.45
+2020-07-05 06:00:00+00:00,-13.87
+2020-07-05 07:00:00+00:00,-14.54
+2020-07-05 08:00:00+00:00,-17.01
+2020-07-05 09:00:00+00:00,-26.93
+2020-07-05 10:00:00+00:00,-63.02
+2020-07-05 11:00:00+00:00,-64.55
+2020-07-05 12:00:00+00:00,-64.99
+2020-07-05 13:00:00+00:00,-64.96
+2020-07-05 14:00:00+00:00,-64.59
+2020-07-05 15:00:00+00:00,-36.97
+2020-07-05 16:00:00+00:00,-4.44
+2020-07-05 17:00:00+00:00,1.49
+2020-07-05 18:00:00+00:00,19.17
+2020-07-05 19:00:00+00:00,25.94
+2020-07-05 20:00:00+00:00,30.24
+2020-07-05 21:00:00+00:00,23.19
+2020-07-05 22:00:00+00:00,19.9
+2020-07-05 23:00:00+00:00,7.71
+2020-07-06 00:00:00+00:00,6.45
+2020-07-06 01:00:00+00:00,3.37
+2020-07-06 02:00:00+00:00,3.23
+2020-07-06 03:00:00+00:00,5.61
+2020-07-06 04:00:00+00:00,20.42
+2020-07-06 05:00:00+00:00,28.27
+2020-07-06 06:00:00+00:00,27.97
+2020-07-06 07:00:00+00:00,21.89
+2020-07-06 08:00:00+00:00,1.49
+2020-07-06 09:00:00+00:00,1.1
+2020-07-06 10:00:00+00:00,1.25
+2020-07-06 11:00:00+00:00,0.05
+2020-07-06 12:00:00+00:00,-3.05
+2020-07-06 13:00:00+00:00,-2.97
+2020-07-06 14:00:00+00:00,-0.02
+2020-07-06 15:00:00+00:00,1.23
+2020-07-06 16:00:00+00:00,27.96
+2020-07-06 17:00:00+00:00,34.22
+2020-07-06 18:00:00+00:00,34.51
+2020-07-06 19:00:00+00:00,35.31
+2020-07-06 20:00:00+00:00,35.94
+2020-07-06 21:00:00+00:00,30.94
+2020-07-06 22:00:00+00:00,29.56
+2020-07-06 23:00:00+00:00,28.54
+2020-07-07 00:00:00+00:00,27.96
+2020-07-07 01:00:00+00:00,27.3
+2020-07-07 02:00:00+00:00,27.15
+2020-07-07 03:00:00+00:00,27.9
+2020-07-07 04:00:00+00:00,33.83
+2020-07-07 05:00:00+00:00,37.65
+2020-07-07 06:00:00+00:00,37.2
+2020-07-07 07:00:00+00:00,34.87
+2020-07-07 08:00:00+00:00,30.82
+2020-07-07 09:00:00+00:00,27.99
+2020-07-07 10:00:00+00:00,27.73
+2020-07-07 11:00:00+00:00,24.98
+2020-07-07 12:00:00+00:00,24.36
+2020-07-07 13:00:00+00:00,24.8
+2020-07-07 14:00:00+00:00,25.18
+2020-07-07 15:00:00+00:00,30.48
+2020-07-07 16:00:00+00:00,38.48
+2020-07-07 17:00:00+00:00,40.78
+2020-07-07 18:00:00+00:00,40.84
+2020-07-07 19:00:00+00:00,40.1
+2020-07-07 20:00:00+00:00,40.15
+2020-07-07 21:00:00+00:00,37.0
+2020-07-07 22:00:00+00:00,35.93
+2020-07-07 23:00:00+00:00,31.05
+2020-07-08 00:00:00+00:00,30.41
+2020-07-08 01:00:00+00:00,29.92
+2020-07-08 02:00:00+00:00,29.55
+2020-07-08 03:00:00+00:00,30.3
+2020-07-08 04:00:00+00:00,36.98
+2020-07-08 05:00:00+00:00,43.0
+2020-07-08 06:00:00+00:00,47.0
+2020-07-08 07:00:00+00:00,46.2
+2020-07-08 08:00:00+00:00,44.44
+2020-07-08 09:00:00+00:00,44.71
+2020-07-08 10:00:00+00:00,42.02
+2020-07-08 11:00:00+00:00,41.09
+2020-07-08 12:00:00+00:00,40.2
+2020-07-08 13:00:00+00:00,39.99
+2020-07-08 14:00:00+00:00,40.02
+2020-07-08 15:00:00+00:00,45.05
+2020-07-08 16:00:00+00:00,52.13
+2020-07-08 17:00:00+00:00,55.0
+2020-07-08 18:00:00+00:00,52.92
+2020-07-08 19:00:00+00:00,45.93
+2020-07-08 20:00:00+00:00,45.49
+2020-07-08 21:00:00+00:00,39.8
+2020-07-08 22:00:00+00:00,39.94
+2020-07-08 23:00:00+00:00,35.41
+2020-07-09 00:00:00+00:00,32.66
+2020-07-09 01:00:00+00:00,30.21
+2020-07-09 02:00:00+00:00,30.99
+2020-07-09 03:00:00+00:00,34.37
+2020-07-09 04:00:00+00:00,42.9
+2020-07-09 05:00:00+00:00,51.96
+2020-07-09 06:00:00+00:00,51.18
+2020-07-09 07:00:00+00:00,47.94
+2020-07-09 08:00:00+00:00,47.08
+2020-07-09 09:00:00+00:00,47.56
+2020-07-09 10:00:00+00:00,43.23
+2020-07-09 11:00:00+00:00,42.53
+2020-07-09 12:00:00+00:00,40.11
+2020-07-09 13:00:00+00:00,39.84
+2020-07-09 14:00:00+00:00,39.9
+2020-07-09 15:00:00+00:00,41.78
+2020-07-09 16:00:00+00:00,46.35
+2020-07-09 17:00:00+00:00,51.7
+2020-07-09 18:00:00+00:00,47.39
+2020-07-09 19:00:00+00:00,46.22
+2020-07-09 20:00:00+00:00,45.0
+2020-07-09 21:00:00+00:00,41.91
+2020-07-09 22:00:00+00:00,39.0
+2020-07-09 23:00:00+00:00,34.62
+2020-07-10 00:00:00+00:00,32.94
+2020-07-10 01:00:00+00:00,31.1
+2020-07-10 02:00:00+00:00,30.52
+2020-07-10 03:00:00+00:00,32.05
+2020-07-10 04:00:00+00:00,38.06
+2020-07-10 05:00:00+00:00,41.01
+2020-07-10 06:00:00+00:00,42.94
+2020-07-10 07:00:00+00:00,42.54
+2020-07-10 08:00:00+00:00,41.76
+2020-07-10 09:00:00+00:00,39.95
+2020-07-10 10:00:00+00:00,38.43
+2020-07-10 11:00:00+00:00,35.41
+2020-07-10 12:00:00+00:00,29.54
+2020-07-10 13:00:00+00:00,29.17
+2020-07-10 14:00:00+00:00,30.5
+2020-07-10 15:00:00+00:00,35.34
+2020-07-10 16:00:00+00:00,38.98
+2020-07-10 17:00:00+00:00,40.79
+2020-07-10 18:00:00+00:00,39.0
+2020-07-10 19:00:00+00:00,39.0
+2020-07-10 20:00:00+00:00,39.4
+2020-07-10 21:00:00+00:00,36.8
+2020-07-10 22:00:00+00:00,34.57
+2020-07-10 23:00:00+00:00,29.9
+2020-07-11 00:00:00+00:00,28.37
+2020-07-11 01:00:00+00:00,27.13
+2020-07-11 02:00:00+00:00,26.1
+2020-07-11 03:00:00+00:00,26.1
+2020-07-11 04:00:00+00:00,26.09
+2020-07-11 05:00:00+00:00,27.58
+2020-07-11 06:00:00+00:00,29.09
+2020-07-11 07:00:00+00:00,28.34
+2020-07-11 08:00:00+00:00,26.53
+2020-07-11 09:00:00+00:00,25.62
+2020-07-11 10:00:00+00:00,23.29
+2020-07-11 11:00:00+00:00,22.86
+2020-07-11 12:00:00+00:00,22.42
+2020-07-11 13:00:00+00:00,22.45
+2020-07-11 14:00:00+00:00,24.36
+2020-07-11 15:00:00+00:00,26.5
+2020-07-11 16:00:00+00:00,30.42
+2020-07-11 17:00:00+00:00,34.0
+2020-07-11 18:00:00+00:00,36.15
+2020-07-11 19:00:00+00:00,35.91
+2020-07-11 20:00:00+00:00,37.73
+2020-07-11 21:00:00+00:00,34.92
+2020-07-11 22:00:00+00:00,32.97
+2020-07-11 23:00:00+00:00,28.82
+2020-07-12 00:00:00+00:00,26.19
+2020-07-12 01:00:00+00:00,25.03
+2020-07-12 02:00:00+00:00,24.7
+2020-07-12 03:00:00+00:00,24.1
+2020-07-12 04:00:00+00:00,21.68
+2020-07-12 05:00:00+00:00,22.69
+2020-07-12 06:00:00+00:00,18.41
+2020-07-12 07:00:00+00:00,18.04
+2020-07-12 08:00:00+00:00,16.97
+2020-07-12 09:00:00+00:00,16.07
+2020-07-12 10:00:00+00:00,18.62
+2020-07-12 11:00:00+00:00,16.04
+2020-07-12 12:00:00+00:00,14.76
+2020-07-12 13:00:00+00:00,15.8
+2020-07-12 14:00:00+00:00,18.11
+2020-07-12 15:00:00+00:00,23.97
+2020-07-12 16:00:00+00:00,29.05
+2020-07-12 17:00:00+00:00,35.12
+2020-07-12 18:00:00+00:00,37.33
+2020-07-12 19:00:00+00:00,37.74
+2020-07-12 20:00:00+00:00,37.08
+2020-07-12 21:00:00+00:00,35.23
+2020-07-12 22:00:00+00:00,29.48
+2020-07-12 23:00:00+00:00,26.03
+2020-07-13 00:00:00+00:00,25.07
+2020-07-13 01:00:00+00:00,25.07
+2020-07-13 02:00:00+00:00,25.1
+2020-07-13 03:00:00+00:00,26.51
+2020-07-13 04:00:00+00:00,34.64
+2020-07-13 05:00:00+00:00,39.52
+2020-07-13 06:00:00+00:00,38.12
+2020-07-13 07:00:00+00:00,37.68
+2020-07-13 08:00:00+00:00,34.05
+2020-07-13 09:00:00+00:00,32.6
+2020-07-13 10:00:00+00:00,31.13
+2020-07-13 11:00:00+00:00,31.18
+2020-07-13 12:00:00+00:00,32.08
+2020-07-13 13:00:00+00:00,31.96
+2020-07-13 14:00:00+00:00,34.0
+2020-07-13 15:00:00+00:00,37.41
+2020-07-13 16:00:00+00:00,40.8
+2020-07-13 17:00:00+00:00,45.56
+2020-07-13 18:00:00+00:00,44.76
+2020-07-13 19:00:00+00:00,41.01
+2020-07-13 20:00:00+00:00,40.05
+2020-07-13 21:00:00+00:00,36.4
+2020-07-13 22:00:00+00:00,34.47
+2020-07-13 23:00:00+00:00,29.79
+2020-07-14 00:00:00+00:00,28.16
+2020-07-14 01:00:00+00:00,27.74
+2020-07-14 02:00:00+00:00,27.45
+2020-07-14 03:00:00+00:00,28.52
+2020-07-14 04:00:00+00:00,35.85
+2020-07-14 05:00:00+00:00,42.91
+2020-07-14 06:00:00+00:00,38.93
+2020-07-14 07:00:00+00:00,36.63
+2020-07-14 08:00:00+00:00,36.15
+2020-07-14 09:00:00+00:00,36.52
+2020-07-14 10:00:00+00:00,36.98
+2020-07-14 11:00:00+00:00,36.97
+2020-07-14 12:00:00+00:00,36.57
+2020-07-14 13:00:00+00:00,36.57
+2020-07-14 14:00:00+00:00,36.2
+2020-07-14 15:00:00+00:00,38.69
+2020-07-14 16:00:00+00:00,44.74
+2020-07-14 17:00:00+00:00,45.97
+2020-07-14 18:00:00+00:00,46.08
+2020-07-14 19:00:00+00:00,41.98
+2020-07-14 20:00:00+00:00,41.43
+2020-07-14 21:00:00+00:00,37.02
+2020-07-14 22:00:00+00:00,35.55
+2020-07-14 23:00:00+00:00,30.22
+2020-07-15 00:00:00+00:00,30.0
+2020-07-15 01:00:00+00:00,28.73
+2020-07-15 02:00:00+00:00,29.84
+2020-07-15 03:00:00+00:00,34.29
+2020-07-15 04:00:00+00:00,41.05
+2020-07-15 05:00:00+00:00,48.91
+2020-07-15 06:00:00+00:00,57.38
+2020-07-15 07:00:00+00:00,47.9
+2020-07-15 08:00:00+00:00,46.07
+2020-07-15 09:00:00+00:00,50.95
+2020-07-15 10:00:00+00:00,46.57
+2020-07-15 11:00:00+00:00,43.78
+2020-07-15 12:00:00+00:00,41.86
+2020-07-15 13:00:00+00:00,42.1
+2020-07-15 14:00:00+00:00,39.4
+2020-07-15 15:00:00+00:00,41.71
+2020-07-15 16:00:00+00:00,44.52
+2020-07-15 17:00:00+00:00,47.3
+2020-07-15 18:00:00+00:00,44.93
+2020-07-15 19:00:00+00:00,47.91
+2020-07-15 20:00:00+00:00,42.09
+2020-07-15 21:00:00+00:00,37.97
+2020-07-15 22:00:00+00:00,36.19
+2020-07-15 23:00:00+00:00,32.5
+2020-07-16 00:00:00+00:00,29.84
+2020-07-16 01:00:00+00:00,28.97
+2020-07-16 02:00:00+00:00,29.35
+2020-07-16 03:00:00+00:00,32.29
+2020-07-16 04:00:00+00:00,43.11
+2020-07-16 05:00:00+00:00,50.9
+2020-07-16 06:00:00+00:00,56.18
+2020-07-16 07:00:00+00:00,58.04
+2020-07-16 08:00:00+00:00,58.7
+2020-07-16 09:00:00+00:00,53.87
+2020-07-16 10:00:00+00:00,52.62
+2020-07-16 11:00:00+00:00,44.41
+2020-07-16 12:00:00+00:00,43.93
+2020-07-16 13:00:00+00:00,44.03
+2020-07-16 14:00:00+00:00,44.01
+2020-07-16 15:00:00+00:00,48.92
+2020-07-16 16:00:00+00:00,45.38
+2020-07-16 17:00:00+00:00,48.39
+2020-07-16 18:00:00+00:00,54.56
+2020-07-16 19:00:00+00:00,48.43
+2020-07-16 20:00:00+00:00,43.1
+2020-07-16 21:00:00+00:00,38.98
+2020-07-16 22:00:00+00:00,36.48
+2020-07-16 23:00:00+00:00,31.85
+2020-07-17 00:00:00+00:00,29.51
+2020-07-17 01:00:00+00:00,28.68
+2020-07-17 02:00:00+00:00,28.76
+2020-07-17 03:00:00+00:00,32.55
+2020-07-17 04:00:00+00:00,40.32
+2020-07-17 05:00:00+00:00,42.74
+2020-07-17 06:00:00+00:00,44.86
+2020-07-17 07:00:00+00:00,42.72
+2020-07-17 08:00:00+00:00,41.25
+2020-07-17 09:00:00+00:00,41.38
+2020-07-17 10:00:00+00:00,39.01
+2020-07-17 11:00:00+00:00,37.0
+2020-07-17 12:00:00+00:00,35.74
+2020-07-17 13:00:00+00:00,34.55
+2020-07-17 14:00:00+00:00,34.95
+2020-07-17 15:00:00+00:00,38.0
+2020-07-17 16:00:00+00:00,41.01
+2020-07-17 17:00:00+00:00,42.01
+2020-07-17 18:00:00+00:00,41.24
+2020-07-17 19:00:00+00:00,40.31
+2020-07-17 20:00:00+00:00,40.93
+2020-07-17 21:00:00+00:00,36.0
+2020-07-17 22:00:00+00:00,34.57
+2020-07-17 23:00:00+00:00,30.54
+2020-07-18 00:00:00+00:00,27.62
+2020-07-18 01:00:00+00:00,26.63
+2020-07-18 02:00:00+00:00,26.0
+2020-07-18 03:00:00+00:00,25.75
+2020-07-18 04:00:00+00:00,25.8
+2020-07-18 05:00:00+00:00,26.5
+2020-07-18 06:00:00+00:00,26.87
+2020-07-18 07:00:00+00:00,26.73
+2020-07-18 08:00:00+00:00,24.35
+2020-07-18 09:00:00+00:00,23.99
+2020-07-18 10:00:00+00:00,23.09
+2020-07-18 11:00:00+00:00,23.15
+2020-07-18 12:00:00+00:00,23.12
+2020-07-18 13:00:00+00:00,23.47
+2020-07-18 14:00:00+00:00,24.15
+2020-07-18 15:00:00+00:00,28.0
+2020-07-18 16:00:00+00:00,34.65
+2020-07-18 17:00:00+00:00,37.95
+2020-07-18 18:00:00+00:00,38.41
+2020-07-18 19:00:00+00:00,38.0
+2020-07-18 20:00:00+00:00,39.45
+2020-07-18 21:00:00+00:00,37.52
+2020-07-18 22:00:00+00:00,34.0
+2020-07-18 23:00:00+00:00,28.36
+2020-07-19 00:00:00+00:00,27.0
+2020-07-19 01:00:00+00:00,25.4
+2020-07-19 02:00:00+00:00,25.02
+2020-07-19 03:00:00+00:00,25.06
+2020-07-19 04:00:00+00:00,24.94
+2020-07-19 05:00:00+00:00,25.4
+2020-07-19 06:00:00+00:00,24.91
+2020-07-19 07:00:00+00:00,24.93
+2020-07-19 08:00:00+00:00,24.72
+2020-07-19 09:00:00+00:00,23.49
+2020-07-19 10:00:00+00:00,23.19
+2020-07-19 11:00:00+00:00,21.13
+2020-07-19 12:00:00+00:00,19.46
+2020-07-19 13:00:00+00:00,20.89
+2020-07-19 14:00:00+00:00,24.28
+2020-07-19 15:00:00+00:00,26.0
+2020-07-19 16:00:00+00:00,29.8
+2020-07-19 17:00:00+00:00,36.15
+2020-07-19 18:00:00+00:00,37.52
+2020-07-19 19:00:00+00:00,37.95
+2020-07-19 20:00:00+00:00,40.42
+2020-07-19 21:00:00+00:00,36.69
+2020-07-19 22:00:00+00:00,32.02
+2020-07-19 23:00:00+00:00,27.57
+2020-07-20 00:00:00+00:00,26.4
+2020-07-20 01:00:00+00:00,26.01
+2020-07-20 02:00:00+00:00,26.0
+2020-07-20 03:00:00+00:00,27.09
+2020-07-20 04:00:00+00:00,35.24
+2020-07-20 05:00:00+00:00,38.29
+2020-07-20 06:00:00+00:00,39.0
+2020-07-20 07:00:00+00:00,38.22
+2020-07-20 08:00:00+00:00,36.35
+2020-07-20 09:00:00+00:00,30.95
+2020-07-20 10:00:00+00:00,26.34
+2020-07-20 11:00:00+00:00,25.15
+2020-07-20 12:00:00+00:00,25.36
+2020-07-20 13:00:00+00:00,25.11
+2020-07-20 14:00:00+00:00,25.93
+2020-07-20 15:00:00+00:00,35.19
+2020-07-20 16:00:00+00:00,39.12
+2020-07-20 17:00:00+00:00,42.54
+2020-07-20 18:00:00+00:00,43.9
+2020-07-20 19:00:00+00:00,41.0
+2020-07-20 20:00:00+00:00,40.8
+2020-07-20 21:00:00+00:00,37.52
+2020-07-20 22:00:00+00:00,31.38
+2020-07-20 23:00:00+00:00,27.85
+2020-07-21 00:00:00+00:00,27.08
+2020-07-21 01:00:00+00:00,26.95
+2020-07-21 02:00:00+00:00,26.98
+2020-07-21 03:00:00+00:00,28.05
+2020-07-21 04:00:00+00:00,35.84
+2020-07-21 05:00:00+00:00,39.07
+2020-07-21 06:00:00+00:00,38.28
+2020-07-21 07:00:00+00:00,35.25
+2020-07-21 08:00:00+00:00,27.79
+2020-07-21 09:00:00+00:00,26.17
+2020-07-21 10:00:00+00:00,26.31
+2020-07-21 11:00:00+00:00,24.83
+2020-07-21 12:00:00+00:00,22.46
+2020-07-21 13:00:00+00:00,24.01
+2020-07-21 14:00:00+00:00,24.75
+2020-07-21 15:00:00+00:00,28.1
+2020-07-21 16:00:00+00:00,38.07
+2020-07-21 17:00:00+00:00,42.74
+2020-07-21 18:00:00+00:00,41.82
+2020-07-21 19:00:00+00:00,40.48
+2020-07-21 20:00:00+00:00,39.73
+2020-07-21 21:00:00+00:00,37.13
+2020-07-21 22:00:00+00:00,33.31
+2020-07-21 23:00:00+00:00,28.39
+2020-07-22 00:00:00+00:00,27.17
+2020-07-22 01:00:00+00:00,26.07
+2020-07-22 02:00:00+00:00,26.05
+2020-07-22 03:00:00+00:00,28.78
+2020-07-22 04:00:00+00:00,35.18
+2020-07-22 05:00:00+00:00,39.4
+2020-07-22 06:00:00+00:00,38.9
+2020-07-22 07:00:00+00:00,37.67
+2020-07-22 08:00:00+00:00,34.44
+2020-07-22 09:00:00+00:00,32.31
+2020-07-22 10:00:00+00:00,29.5
+2020-07-22 11:00:00+00:00,28.19
+2020-07-22 12:00:00+00:00,26.97
+2020-07-22 13:00:00+00:00,29.0
+2020-07-22 14:00:00+00:00,31.69
+2020-07-22 15:00:00+00:00,38.83
+2020-07-22 16:00:00+00:00,42.19
+2020-07-22 17:00:00+00:00,45.74
+2020-07-22 18:00:00+00:00,44.34
+2020-07-22 19:00:00+00:00,41.96
+2020-07-22 20:00:00+00:00,41.44
+2020-07-22 21:00:00+00:00,36.92
+2020-07-22 22:00:00+00:00,35.96
+2020-07-22 23:00:00+00:00,32.98
+2020-07-23 00:00:00+00:00,31.0
+2020-07-23 01:00:00+00:00,29.86
+2020-07-23 02:00:00+00:00,28.99
+2020-07-23 03:00:00+00:00,31.43
+2020-07-23 04:00:00+00:00,40.33
+2020-07-23 05:00:00+00:00,45.89
+2020-07-23 06:00:00+00:00,39.36
+2020-07-23 07:00:00+00:00,37.67
+2020-07-23 08:00:00+00:00,33.92
+2020-07-23 09:00:00+00:00,30.97
+2020-07-23 10:00:00+00:00,30.76
+2020-07-23 11:00:00+00:00,29.25
+2020-07-23 12:00:00+00:00,27.9
+2020-07-23 13:00:00+00:00,29.69
+2020-07-23 14:00:00+00:00,30.93
+2020-07-23 15:00:00+00:00,38.19
+2020-07-23 16:00:00+00:00,42.86
+2020-07-23 17:00:00+00:00,45.23
+2020-07-23 18:00:00+00:00,43.64
+2020-07-23 19:00:00+00:00,42.09
+2020-07-23 20:00:00+00:00,41.69
+2020-07-23 21:00:00+00:00,36.0
+2020-07-23 22:00:00+00:00,31.72
+2020-07-23 23:00:00+00:00,25.63
+2020-07-24 00:00:00+00:00,23.94
+2020-07-24 01:00:00+00:00,22.94
+2020-07-24 02:00:00+00:00,23.71
+2020-07-24 03:00:00+00:00,25.22
+2020-07-24 04:00:00+00:00,30.09
+2020-07-24 05:00:00+00:00,36.14
+2020-07-24 06:00:00+00:00,39.95
+2020-07-24 07:00:00+00:00,39.83
+2020-07-24 08:00:00+00:00,40.02
+2020-07-24 09:00:00+00:00,36.04
+2020-07-24 10:00:00+00:00,29.57
+2020-07-24 11:00:00+00:00,26.04
+2020-07-24 12:00:00+00:00,24.2
+2020-07-24 13:00:00+00:00,24.01
+2020-07-24 14:00:00+00:00,23.85
+2020-07-24 15:00:00+00:00,26.75
+2020-07-24 16:00:00+00:00,34.97
+2020-07-24 17:00:00+00:00,36.85
+2020-07-24 18:00:00+00:00,37.39
+2020-07-24 19:00:00+00:00,37.04
+2020-07-24 20:00:00+00:00,37.17
+2020-07-24 21:00:00+00:00,34.65
+2020-07-24 22:00:00+00:00,34.63
+2020-07-24 23:00:00+00:00,30.56
+2020-07-25 00:00:00+00:00,27.93
+2020-07-25 01:00:00+00:00,26.03
+2020-07-25 02:00:00+00:00,25.0
+2020-07-25 03:00:00+00:00,25.04
+2020-07-25 04:00:00+00:00,25.18
+2020-07-25 05:00:00+00:00,26.3
+2020-07-25 06:00:00+00:00,26.29
+2020-07-25 07:00:00+00:00,23.95
+2020-07-25 08:00:00+00:00,20.82
+2020-07-25 09:00:00+00:00,20.18
+2020-07-25 10:00:00+00:00,20.26
+2020-07-25 11:00:00+00:00,17.87
+2020-07-25 12:00:00+00:00,18.15
+2020-07-25 13:00:00+00:00,18.45
+2020-07-25 14:00:00+00:00,19.78
+2020-07-25 15:00:00+00:00,25.01
+2020-07-25 16:00:00+00:00,28.9
+2020-07-25 17:00:00+00:00,31.58
+2020-07-25 18:00:00+00:00,32.22
+2020-07-25 19:00:00+00:00,31.41
+2020-07-25 20:00:00+00:00,32.15
+2020-07-25 21:00:00+00:00,24.79
+2020-07-25 22:00:00+00:00,23.78
+2020-07-25 23:00:00+00:00,21.6
+2020-07-26 00:00:00+00:00,20.37
+2020-07-26 01:00:00+00:00,17.0
+2020-07-26 02:00:00+00:00,17.1
+2020-07-26 03:00:00+00:00,16.5
+2020-07-26 04:00:00+00:00,10.7
+2020-07-26 05:00:00+00:00,10.82
+2020-07-26 06:00:00+00:00,15.88
+2020-07-26 07:00:00+00:00,17.83
+2020-07-26 08:00:00+00:00,9.9
+2020-07-26 09:00:00+00:00,2.0
+2020-07-26 10:00:00+00:00,0.84
+2020-07-26 11:00:00+00:00,-5.82
+2020-07-26 12:00:00+00:00,-44.97
+2020-07-26 13:00:00+00:00,-21.35
+2020-07-26 14:00:00+00:00,-2.07
+2020-07-26 15:00:00+00:00,6.77
+2020-07-26 16:00:00+00:00,22.64
+2020-07-26 17:00:00+00:00,25.64
+2020-07-26 18:00:00+00:00,32.7
+2020-07-26 19:00:00+00:00,35.69
+2020-07-26 20:00:00+00:00,36.97
+2020-07-26 21:00:00+00:00,32.04
+2020-07-26 22:00:00+00:00,32.43
+2020-07-26 23:00:00+00:00,27.11
+2020-07-27 00:00:00+00:00,25.8
+2020-07-27 01:00:00+00:00,24.15
+2020-07-27 02:00:00+00:00,24.02
+2020-07-27 03:00:00+00:00,27.18
+2020-07-27 04:00:00+00:00,35.86
+2020-07-27 05:00:00+00:00,37.95
+2020-07-27 06:00:00+00:00,38.59
+2020-07-27 07:00:00+00:00,38.72
+2020-07-27 08:00:00+00:00,36.87
+2020-07-27 09:00:00+00:00,35.45
+2020-07-27 10:00:00+00:00,32.18
+2020-07-27 11:00:00+00:00,30.54
+2020-07-27 12:00:00+00:00,30.46
+2020-07-27 13:00:00+00:00,31.4
+2020-07-27 14:00:00+00:00,34.44
+2020-07-27 15:00:00+00:00,36.44
+2020-07-27 16:00:00+00:00,38.5
+2020-07-27 17:00:00+00:00,39.36
+2020-07-27 18:00:00+00:00,37.98
+2020-07-27 19:00:00+00:00,33.72
+2020-07-27 20:00:00+00:00,29.0
+2020-07-27 21:00:00+00:00,22.62
+2020-07-27 22:00:00+00:00,18.71
+2020-07-27 23:00:00+00:00,19.16
+2020-07-28 00:00:00+00:00,16.82
+2020-07-28 01:00:00+00:00,17.2
+2020-07-28 02:00:00+00:00,17.11
+2020-07-28 03:00:00+00:00,21.56
+2020-07-28 04:00:00+00:00,26.21
+2020-07-28 05:00:00+00:00,32.17
+2020-07-28 06:00:00+00:00,33.32
+2020-07-28 07:00:00+00:00,28.62
+2020-07-28 08:00:00+00:00,23.58
+2020-07-28 09:00:00+00:00,21.04
+2020-07-28 10:00:00+00:00,14.93
+2020-07-28 11:00:00+00:00,0.04
+2020-07-28 12:00:00+00:00,1.48
+2020-07-28 13:00:00+00:00,8.13
+2020-07-28 14:00:00+00:00,21.03
+2020-07-28 15:00:00+00:00,27.09
+2020-07-28 16:00:00+00:00,30.96
+2020-07-28 17:00:00+00:00,35.78
+2020-07-28 18:00:00+00:00,36.94
+2020-07-28 19:00:00+00:00,36.78
+2020-07-28 20:00:00+00:00,34.21
+2020-07-28 21:00:00+00:00,28.31
+2020-07-28 22:00:00+00:00,26.16
+2020-07-28 23:00:00+00:00,23.5
+2020-07-29 00:00:00+00:00,23.53
+2020-07-29 01:00:00+00:00,22.38
+2020-07-29 02:00:00+00:00,22.79
+2020-07-29 03:00:00+00:00,23.65
+2020-07-29 04:00:00+00:00,29.78
+2020-07-29 05:00:00+00:00,32.85
+2020-07-29 06:00:00+00:00,30.59
+2020-07-29 07:00:00+00:00,22.73
+2020-07-29 08:00:00+00:00,10.65
+2020-07-29 09:00:00+00:00,3.56
+2020-07-29 10:00:00+00:00,0.13
+2020-07-29 11:00:00+00:00,0.07
+2020-07-29 12:00:00+00:00,0.07
+2020-07-29 13:00:00+00:00,0.08
+2020-07-29 14:00:00+00:00,3.77
+2020-07-29 15:00:00+00:00,14.74
+2020-07-29 16:00:00+00:00,26.74
+2020-07-29 17:00:00+00:00,34.02
+2020-07-29 18:00:00+00:00,35.61
+2020-07-29 19:00:00+00:00,39.38
+2020-07-29 20:00:00+00:00,37.0
+2020-07-29 21:00:00+00:00,34.2
+2020-07-29 22:00:00+00:00,35.97
+2020-07-29 23:00:00+00:00,31.78
+2020-07-30 00:00:00+00:00,29.1
+2020-07-30 01:00:00+00:00,27.17
+2020-07-30 02:00:00+00:00,26.99
+2020-07-30 03:00:00+00:00,29.2
+2020-07-30 04:00:00+00:00,36.91
+2020-07-30 05:00:00+00:00,39.64
+2020-07-30 06:00:00+00:00,39.53
+2020-07-30 07:00:00+00:00,34.88
+2020-07-30 08:00:00+00:00,28.14
+2020-07-30 09:00:00+00:00,27.49
+2020-07-30 10:00:00+00:00,26.73
+2020-07-30 11:00:00+00:00,25.55
+2020-07-30 12:00:00+00:00,26.2
+2020-07-30 13:00:00+00:00,27.59
+2020-07-30 14:00:00+00:00,30.25
+2020-07-30 15:00:00+00:00,38.08
+2020-07-30 16:00:00+00:00,44.94
+2020-07-30 17:00:00+00:00,60.02
+2020-07-30 18:00:00+00:00,56.8
+2020-07-30 19:00:00+00:00,49.83
+2020-07-30 20:00:00+00:00,44.54
+2020-07-30 21:00:00+00:00,37.53
+2020-07-30 22:00:00+00:00,38.8
+2020-07-30 23:00:00+00:00,33.9
+2020-07-31 00:00:00+00:00,31.99
+2020-07-31 01:00:00+00:00,31.58
+2020-07-31 02:00:00+00:00,31.74
+2020-07-31 03:00:00+00:00,34.28
+2020-07-31 04:00:00+00:00,40.56
+2020-07-31 05:00:00+00:00,43.69
+2020-07-31 06:00:00+00:00,44.91
+2020-07-31 07:00:00+00:00,41.65
+2020-07-31 08:00:00+00:00,38.25
+2020-07-31 09:00:00+00:00,32.7
+2020-07-31 10:00:00+00:00,30.49
+2020-07-31 11:00:00+00:00,29.49
+2020-07-31 12:00:00+00:00,30.09
+2020-07-31 13:00:00+00:00,31.95
+2020-07-31 14:00:00+00:00,33.49
+2020-07-31 15:00:00+00:00,42.66
+2020-07-31 16:00:00+00:00,49.08
+2020-07-31 17:00:00+00:00,54.4
+2020-07-31 18:00:00+00:00,49.12
+2020-07-31 19:00:00+00:00,46.15
+2020-07-31 20:00:00+00:00,44.97
+2020-07-31 21:00:00+00:00,38.27
+2020-07-31 22:00:00+00:00,33.35
+2020-07-31 23:00:00+00:00,24.6
+2020-08-01 00:00:00+00:00,24.28
+2020-08-01 01:00:00+00:00,23.99
+2020-08-01 02:00:00+00:00,23.67
+2020-08-01 03:00:00+00:00,24.0
+2020-08-01 04:00:00+00:00,25.0
+2020-08-01 05:00:00+00:00,27.59
+2020-08-01 06:00:00+00:00,25.93
+2020-08-01 07:00:00+00:00,24.4
+2020-08-01 08:00:00+00:00,23.22
+2020-08-01 09:00:00+00:00,23.37
+2020-08-01 10:00:00+00:00,24.31
+2020-08-01 11:00:00+00:00,23.74
+2020-08-01 12:00:00+00:00,23.11
+2020-08-01 13:00:00+00:00,23.16
+2020-08-01 14:00:00+00:00,25.54
+2020-08-01 15:00:00+00:00,32.62
+2020-08-01 16:00:00+00:00,38.43
+2020-08-01 17:00:00+00:00,38.78
+2020-08-01 18:00:00+00:00,38.37
+2020-08-01 19:00:00+00:00,37.78
+2020-08-01 20:00:00+00:00,37.12
+2020-08-01 21:00:00+00:00,33.09
+2020-08-01 22:00:00+00:00,30.67
+2020-08-01 23:00:00+00:00,27.82
+2020-08-02 00:00:00+00:00,26.97
+2020-08-02 01:00:00+00:00,25.25
+2020-08-02 02:00:00+00:00,25.23
+2020-08-02 03:00:00+00:00,25.09
+2020-08-02 04:00:00+00:00,25.46
+2020-08-02 05:00:00+00:00,26.09
+2020-08-02 06:00:00+00:00,27.4
+2020-08-02 07:00:00+00:00,27.62
+2020-08-02 08:00:00+00:00,27.63
+2020-08-02 09:00:00+00:00,28.01
+2020-08-02 10:00:00+00:00,26.42
+2020-08-02 11:00:00+00:00,24.76
+2020-08-02 12:00:00+00:00,24.53
+2020-08-02 13:00:00+00:00,24.16
+2020-08-02 14:00:00+00:00,23.86
+2020-08-02 15:00:00+00:00,25.56
+2020-08-02 16:00:00+00:00,28.08
+2020-08-02 17:00:00+00:00,33.0
+2020-08-02 18:00:00+00:00,34.14
+2020-08-02 19:00:00+00:00,35.49
+2020-08-02 20:00:00+00:00,38.43
+2020-08-02 21:00:00+00:00,34.89
+2020-08-02 22:00:00+00:00,27.93
+2020-08-02 23:00:00+00:00,26.19
+2020-08-03 00:00:00+00:00,26.05
+2020-08-03 01:00:00+00:00,25.06
+2020-08-03 02:00:00+00:00,26.03
+2020-08-03 03:00:00+00:00,27.93
+2020-08-03 04:00:00+00:00,34.12
+2020-08-03 05:00:00+00:00,39.97
+2020-08-03 06:00:00+00:00,41.0
+2020-08-03 07:00:00+00:00,42.65
+2020-08-03 08:00:00+00:00,41.2
+2020-08-03 09:00:00+00:00,41.16
+2020-08-03 10:00:00+00:00,40.97
+2020-08-03 11:00:00+00:00,39.9
+2020-08-03 12:00:00+00:00,38.24
+2020-08-03 13:00:00+00:00,37.18
+2020-08-03 14:00:00+00:00,37.75
+2020-08-03 15:00:00+00:00,39.67
+2020-08-03 16:00:00+00:00,42.1
+2020-08-03 17:00:00+00:00,45.45
+2020-08-03 18:00:00+00:00,43.06
+2020-08-03 19:00:00+00:00,41.7
+2020-08-03 20:00:00+00:00,40.9
+2020-08-03 21:00:00+00:00,35.05
+2020-08-03 22:00:00+00:00,31.6
+2020-08-03 23:00:00+00:00,28.02
+2020-08-04 00:00:00+00:00,26.14
+2020-08-04 01:00:00+00:00,23.66
+2020-08-04 02:00:00+00:00,23.67
+2020-08-04 03:00:00+00:00,28.35
+2020-08-04 04:00:00+00:00,33.0
+2020-08-04 05:00:00+00:00,46.97
+2020-08-04 06:00:00+00:00,49.67
+2020-08-04 07:00:00+00:00,46.45
+2020-08-04 08:00:00+00:00,41.35
+2020-08-04 09:00:00+00:00,40.33
+2020-08-04 10:00:00+00:00,39.38
+2020-08-04 11:00:00+00:00,36.98
+2020-08-04 12:00:00+00:00,35.22
+2020-08-04 13:00:00+00:00,34.81
+2020-08-04 14:00:00+00:00,33.96
+2020-08-04 15:00:00+00:00,37.77
+2020-08-04 16:00:00+00:00,40.41
+2020-08-04 17:00:00+00:00,41.32
+2020-08-04 18:00:00+00:00,41.2
+2020-08-04 19:00:00+00:00,41.16
+2020-08-04 20:00:00+00:00,39.83
+2020-08-04 21:00:00+00:00,32.2
+2020-08-04 22:00:00+00:00,32.27
+2020-08-04 23:00:00+00:00,26.29
+2020-08-05 00:00:00+00:00,23.51
+2020-08-05 01:00:00+00:00,19.64
+2020-08-05 02:00:00+00:00,19.5
+2020-08-05 03:00:00+00:00,22.85
+2020-08-05 04:00:00+00:00,28.77
+2020-08-05 05:00:00+00:00,33.08
+2020-08-05 06:00:00+00:00,32.67
+2020-08-05 07:00:00+00:00,26.18
+2020-08-05 08:00:00+00:00,24.58
+2020-08-05 09:00:00+00:00,23.91
+2020-08-05 10:00:00+00:00,23.72
+2020-08-05 11:00:00+00:00,23.52
+2020-08-05 12:00:00+00:00,23.79
+2020-08-05 13:00:00+00:00,23.32
+2020-08-05 14:00:00+00:00,24.83
+2020-08-05 15:00:00+00:00,31.22
+2020-08-05 16:00:00+00:00,39.6
+2020-08-05 17:00:00+00:00,43.04
+2020-08-05 18:00:00+00:00,43.4
+2020-08-05 19:00:00+00:00,42.43
+2020-08-05 20:00:00+00:00,41.69
+2020-08-05 21:00:00+00:00,36.71
+2020-08-05 22:00:00+00:00,26.9
+2020-08-05 23:00:00+00:00,23.99
+2020-08-06 00:00:00+00:00,23.12
+2020-08-06 01:00:00+00:00,23.02
+2020-08-06 02:00:00+00:00,24.06
+2020-08-06 03:00:00+00:00,27.09
+2020-08-06 04:00:00+00:00,32.0
+2020-08-06 05:00:00+00:00,36.96
+2020-08-06 06:00:00+00:00,38.45
+2020-08-06 07:00:00+00:00,37.55
+2020-08-06 08:00:00+00:00,28.75
+2020-08-06 09:00:00+00:00,26.63
+2020-08-06 10:00:00+00:00,26.93
+2020-08-06 11:00:00+00:00,26.62
+2020-08-06 12:00:00+00:00,26.6
+2020-08-06 13:00:00+00:00,27.41
+2020-08-06 14:00:00+00:00,34.74
+2020-08-06 15:00:00+00:00,39.69
+2020-08-06 16:00:00+00:00,43.39
+2020-08-06 17:00:00+00:00,53.96
+2020-08-06 18:00:00+00:00,49.22
+2020-08-06 19:00:00+00:00,43.39
+2020-08-06 20:00:00+00:00,41.39
+2020-08-06 21:00:00+00:00,36.86
+2020-08-06 22:00:00+00:00,34.26
+2020-08-06 23:00:00+00:00,31.01
+2020-08-07 00:00:00+00:00,29.2
+2020-08-07 01:00:00+00:00,27.81
+2020-08-07 02:00:00+00:00,27.48
+2020-08-07 03:00:00+00:00,30.66
+2020-08-07 04:00:00+00:00,34.89
+2020-08-07 05:00:00+00:00,39.09
+2020-08-07 06:00:00+00:00,39.2
+2020-08-07 07:00:00+00:00,39.0
+2020-08-07 08:00:00+00:00,36.45
+2020-08-07 09:00:00+00:00,33.37
+2020-08-07 10:00:00+00:00,31.16
+2020-08-07 11:00:00+00:00,30.59
+2020-08-07 12:00:00+00:00,29.92
+2020-08-07 13:00:00+00:00,31.49
+2020-08-07 14:00:00+00:00,34.38
+2020-08-07 15:00:00+00:00,40.11
+2020-08-07 16:00:00+00:00,43.82
+2020-08-07 17:00:00+00:00,50.11
+2020-08-07 18:00:00+00:00,47.07
+2020-08-07 19:00:00+00:00,44.4
+2020-08-07 20:00:00+00:00,42.04
+2020-08-07 21:00:00+00:00,35.99
+2020-08-07 22:00:00+00:00,38.0
+2020-08-07 23:00:00+00:00,32.8
+2020-08-08 00:00:00+00:00,30.96
+2020-08-08 01:00:00+00:00,29.52
+2020-08-08 02:00:00+00:00,28.94
+2020-08-08 03:00:00+00:00,29.5
+2020-08-08 04:00:00+00:00,29.48
+2020-08-08 05:00:00+00:00,31.7
+2020-08-08 06:00:00+00:00,32.64
+2020-08-08 07:00:00+00:00,33.11
+2020-08-08 08:00:00+00:00,29.6
+2020-08-08 09:00:00+00:00,27.59
+2020-08-08 10:00:00+00:00,25.09
+2020-08-08 11:00:00+00:00,24.02
+2020-08-08 12:00:00+00:00,24.71
+2020-08-08 13:00:00+00:00,27.38
+2020-08-08 14:00:00+00:00,28.9
+2020-08-08 15:00:00+00:00,33.2
+2020-08-08 16:00:00+00:00,38.1
+2020-08-08 17:00:00+00:00,40.7
+2020-08-08 18:00:00+00:00,41.2
+2020-08-08 19:00:00+00:00,40.09
+2020-08-08 20:00:00+00:00,38.62
+2020-08-08 21:00:00+00:00,33.08
+2020-08-08 22:00:00+00:00,31.95
+2020-08-08 23:00:00+00:00,29.16
+2020-08-09 00:00:00+00:00,28.0
+2020-08-09 01:00:00+00:00,26.17
+2020-08-09 02:00:00+00:00,25.78
+2020-08-09 03:00:00+00:00,25.8
+2020-08-09 04:00:00+00:00,24.7
+2020-08-09 05:00:00+00:00,24.4
+2020-08-09 06:00:00+00:00,25.03
+2020-08-09 07:00:00+00:00,24.64
+2020-08-09 08:00:00+00:00,26.42
+2020-08-09 09:00:00+00:00,25.37
+2020-08-09 10:00:00+00:00,24.01
+2020-08-09 11:00:00+00:00,23.41
+2020-08-09 12:00:00+00:00,23.43
+2020-08-09 13:00:00+00:00,23.93
+2020-08-09 14:00:00+00:00,27.66
+2020-08-09 15:00:00+00:00,29.46
+2020-08-09 16:00:00+00:00,35.0
+2020-08-09 17:00:00+00:00,39.9
+2020-08-09 18:00:00+00:00,40.24
+2020-08-09 19:00:00+00:00,38.99
+2020-08-09 20:00:00+00:00,35.09
+2020-08-09 21:00:00+00:00,26.27
+2020-08-09 22:00:00+00:00,30.23
+2020-08-09 23:00:00+00:00,28.7
+2020-08-10 00:00:00+00:00,28.03
+2020-08-10 01:00:00+00:00,26.1
+2020-08-10 02:00:00+00:00,26.95
+2020-08-10 03:00:00+00:00,29.13
+2020-08-10 04:00:00+00:00,36.9
+2020-08-10 05:00:00+00:00,41.2
+2020-08-10 06:00:00+00:00,40.35
+2020-08-10 07:00:00+00:00,41.0
+2020-08-10 08:00:00+00:00,40.52
+2020-08-10 09:00:00+00:00,38.83
+2020-08-10 10:00:00+00:00,33.85
+2020-08-10 11:00:00+00:00,32.78
+2020-08-10 12:00:00+00:00,33.06
+2020-08-10 13:00:00+00:00,36.82
+2020-08-10 14:00:00+00:00,39.44
+2020-08-10 15:00:00+00:00,42.21
+2020-08-10 16:00:00+00:00,46.38
+2020-08-10 17:00:00+00:00,52.74
+2020-08-10 18:00:00+00:00,47.29
+2020-08-10 19:00:00+00:00,43.4
+2020-08-10 20:00:00+00:00,40.84
+2020-08-10 21:00:00+00:00,30.74
+2020-08-10 22:00:00+00:00,34.66
+2020-08-10 23:00:00+00:00,33.12
+2020-08-11 00:00:00+00:00,31.12
+2020-08-11 01:00:00+00:00,29.78
+2020-08-11 02:00:00+00:00,30.13
+2020-08-11 03:00:00+00:00,32.33
+2020-08-11 04:00:00+00:00,36.1
+2020-08-11 05:00:00+00:00,40.53
+2020-08-11 06:00:00+00:00,41.26
+2020-08-11 07:00:00+00:00,41.54
+2020-08-11 08:00:00+00:00,39.99
+2020-08-11 09:00:00+00:00,35.22
+2020-08-11 10:00:00+00:00,34.01
+2020-08-11 11:00:00+00:00,32.96
+2020-08-11 12:00:00+00:00,32.16
+2020-08-11 13:00:00+00:00,32.22
+2020-08-11 14:00:00+00:00,38.56
+2020-08-11 15:00:00+00:00,41.55
+2020-08-11 16:00:00+00:00,43.01
+2020-08-11 17:00:00+00:00,46.49
+2020-08-11 18:00:00+00:00,41.31
+2020-08-11 19:00:00+00:00,39.98
+2020-08-11 20:00:00+00:00,35.09
+2020-08-11 21:00:00+00:00,28.02
+2020-08-11 22:00:00+00:00,24.89
+2020-08-11 23:00:00+00:00,24.34
+2020-08-12 00:00:00+00:00,24.35
+2020-08-12 01:00:00+00:00,25.28
+2020-08-12 02:00:00+00:00,27.03
+2020-08-12 03:00:00+00:00,30.44
+2020-08-12 04:00:00+00:00,34.93
+2020-08-12 05:00:00+00:00,39.0
+2020-08-12 06:00:00+00:00,41.4
+2020-08-12 07:00:00+00:00,41.28
+2020-08-12 08:00:00+00:00,38.01
+2020-08-12 09:00:00+00:00,34.44
+2020-08-12 10:00:00+00:00,33.57
+2020-08-12 11:00:00+00:00,33.0
+2020-08-12 12:00:00+00:00,32.79
+2020-08-12 13:00:00+00:00,35.07
+2020-08-12 14:00:00+00:00,36.38
+2020-08-12 15:00:00+00:00,41.71
+2020-08-12 16:00:00+00:00,49.97
+2020-08-12 17:00:00+00:00,56.4
+2020-08-12 18:00:00+00:00,45.87
+2020-08-12 19:00:00+00:00,41.6
+2020-08-12 20:00:00+00:00,37.83
+2020-08-12 21:00:00+00:00,31.17
+2020-08-12 22:00:00+00:00,31.49
+2020-08-12 23:00:00+00:00,29.16
+2020-08-13 00:00:00+00:00,28.42
+2020-08-13 01:00:00+00:00,28.08
+2020-08-13 02:00:00+00:00,28.14
+2020-08-13 03:00:00+00:00,31.47
+2020-08-13 04:00:00+00:00,34.98
+2020-08-13 05:00:00+00:00,39.98
+2020-08-13 06:00:00+00:00,40.97
+2020-08-13 07:00:00+00:00,42.79
+2020-08-13 08:00:00+00:00,41.76
+2020-08-13 09:00:00+00:00,40.65
+2020-08-13 10:00:00+00:00,39.08
+2020-08-13 11:00:00+00:00,38.28
+2020-08-13 12:00:00+00:00,36.8
+2020-08-13 13:00:00+00:00,37.98
+2020-08-13 14:00:00+00:00,39.07
+2020-08-13 15:00:00+00:00,42.62
+2020-08-13 16:00:00+00:00,49.5
+2020-08-13 17:00:00+00:00,53.39
+2020-08-13 18:00:00+00:00,48.91
+2020-08-13 19:00:00+00:00,44.29
+2020-08-13 20:00:00+00:00,42.06
+2020-08-13 21:00:00+00:00,36.19
+2020-08-13 22:00:00+00:00,33.41
+2020-08-13 23:00:00+00:00,32.24
+2020-08-14 00:00:00+00:00,31.07
+2020-08-14 01:00:00+00:00,30.18
+2020-08-14 02:00:00+00:00,30.07
+2020-08-14 03:00:00+00:00,32.1
+2020-08-14 04:00:00+00:00,43.01
+2020-08-14 05:00:00+00:00,51.58
+2020-08-14 06:00:00+00:00,51.08
+2020-08-14 07:00:00+00:00,51.98
+2020-08-14 08:00:00+00:00,53.28
+2020-08-14 09:00:00+00:00,51.63
+2020-08-14 10:00:00+00:00,44.28
+2020-08-14 11:00:00+00:00,39.17
+2020-08-14 12:00:00+00:00,37.61
+2020-08-14 13:00:00+00:00,37.01
+2020-08-14 14:00:00+00:00,38.01
+2020-08-14 15:00:00+00:00,39.94
+2020-08-14 16:00:00+00:00,45.69
+2020-08-14 17:00:00+00:00,46.08
+2020-08-14 18:00:00+00:00,43.0
+2020-08-14 19:00:00+00:00,42.06
+2020-08-14 20:00:00+00:00,40.0
+2020-08-14 21:00:00+00:00,35.35
+2020-08-14 22:00:00+00:00,38.36
+2020-08-14 23:00:00+00:00,33.9
+2020-08-15 00:00:00+00:00,31.77
+2020-08-15 01:00:00+00:00,30.31
+2020-08-15 02:00:00+00:00,29.92
+2020-08-15 03:00:00+00:00,29.06
+2020-08-15 04:00:00+00:00,29.0
+2020-08-15 05:00:00+00:00,29.1
+2020-08-15 06:00:00+00:00,30.38
+2020-08-15 07:00:00+00:00,31.39
+2020-08-15 08:00:00+00:00,30.14
+2020-08-15 09:00:00+00:00,29.91
+2020-08-15 10:00:00+00:00,29.53
+2020-08-15 11:00:00+00:00,28.0
+2020-08-15 12:00:00+00:00,27.14
+2020-08-15 13:00:00+00:00,26.07
+2020-08-15 14:00:00+00:00,27.3
+2020-08-15 15:00:00+00:00,29.11
+2020-08-15 16:00:00+00:00,34.09
+2020-08-15 17:00:00+00:00,36.98
+2020-08-15 18:00:00+00:00,39.59
+2020-08-15 19:00:00+00:00,39.93
+2020-08-15 20:00:00+00:00,39.54
+2020-08-15 21:00:00+00:00,34.14
+2020-08-15 22:00:00+00:00,33.12
+2020-08-15 23:00:00+00:00,29.0
+2020-08-16 00:00:00+00:00,28.0
+2020-08-16 01:00:00+00:00,26.5
+2020-08-16 02:00:00+00:00,26.15
+2020-08-16 03:00:00+00:00,25.7
+2020-08-16 04:00:00+00:00,26.0
+2020-08-16 05:00:00+00:00,25.95
+2020-08-16 06:00:00+00:00,28.0
+2020-08-16 07:00:00+00:00,28.36
+2020-08-16 08:00:00+00:00,25.51
+2020-08-16 09:00:00+00:00,24.11
+2020-08-16 10:00:00+00:00,22.94
+2020-08-16 11:00:00+00:00,21.91
+2020-08-16 12:00:00+00:00,19.66
+2020-08-16 13:00:00+00:00,20.9
+2020-08-16 14:00:00+00:00,22.5
+2020-08-16 15:00:00+00:00,28.11
+2020-08-16 16:00:00+00:00,34.0
+2020-08-16 17:00:00+00:00,36.98
+2020-08-16 18:00:00+00:00,39.77
+2020-08-16 19:00:00+00:00,40.21
+2020-08-16 20:00:00+00:00,39.98
+2020-08-16 21:00:00+00:00,35.07
+2020-08-16 22:00:00+00:00,30.43
+2020-08-16 23:00:00+00:00,28.72
+2020-08-17 00:00:00+00:00,28.25
+2020-08-17 01:00:00+00:00,27.75
+2020-08-17 02:00:00+00:00,27.91
+2020-08-17 03:00:00+00:00,30.13
+2020-08-17 04:00:00+00:00,35.96
+2020-08-17 05:00:00+00:00,41.44
+2020-08-17 06:00:00+00:00,44.55
+2020-08-17 07:00:00+00:00,44.75
+2020-08-17 08:00:00+00:00,42.11
+2020-08-17 09:00:00+00:00,41.91
+2020-08-17 10:00:00+00:00,39.97
+2020-08-17 11:00:00+00:00,38.67
+2020-08-17 12:00:00+00:00,38.09
+2020-08-17 13:00:00+00:00,39.0
+2020-08-17 14:00:00+00:00,41.0
+2020-08-17 15:00:00+00:00,45.0
+2020-08-17 16:00:00+00:00,51.25
+2020-08-17 17:00:00+00:00,61.47
+2020-08-17 18:00:00+00:00,55.52
+2020-08-17 19:00:00+00:00,51.1
+2020-08-17 20:00:00+00:00,45.0
+2020-08-17 21:00:00+00:00,38.74
+2020-08-17 22:00:00+00:00,35.83
+2020-08-17 23:00:00+00:00,33.4
+2020-08-18 00:00:00+00:00,31.49
+2020-08-18 01:00:00+00:00,29.92
+2020-08-18 02:00:00+00:00,29.95
+2020-08-18 03:00:00+00:00,33.31
+2020-08-18 04:00:00+00:00,42.9
+2020-08-18 05:00:00+00:00,50.92
+2020-08-18 06:00:00+00:00,56.67
+2020-08-18 07:00:00+00:00,49.22
+2020-08-18 08:00:00+00:00,44.03
+2020-08-18 09:00:00+00:00,41.21
+2020-08-18 10:00:00+00:00,40.74
+2020-08-18 11:00:00+00:00,37.79
+2020-08-18 12:00:00+00:00,36.45
+2020-08-18 13:00:00+00:00,36.01
+2020-08-18 14:00:00+00:00,37.6
+2020-08-18 15:00:00+00:00,43.68
+2020-08-18 16:00:00+00:00,51.25
+2020-08-18 17:00:00+00:00,58.05
+2020-08-18 18:00:00+00:00,55.66
+2020-08-18 19:00:00+00:00,52.0
+2020-08-18 20:00:00+00:00,49.06
+2020-08-18 21:00:00+00:00,40.29
+2020-08-18 22:00:00+00:00,37.53
+2020-08-18 23:00:00+00:00,33.91
+2020-08-19 00:00:00+00:00,32.52
+2020-08-19 01:00:00+00:00,30.48
+2020-08-19 02:00:00+00:00,30.25
+2020-08-19 03:00:00+00:00,33.43
+2020-08-19 04:00:00+00:00,39.65
+2020-08-19 05:00:00+00:00,46.9
+2020-08-19 06:00:00+00:00,45.04
+2020-08-19 07:00:00+00:00,42.16
+2020-08-19 08:00:00+00:00,38.42
+2020-08-19 09:00:00+00:00,34.98
+2020-08-19 10:00:00+00:00,33.5
+2020-08-19 11:00:00+00:00,33.46
+2020-08-19 12:00:00+00:00,33.25
+2020-08-19 13:00:00+00:00,33.32
+2020-08-19 14:00:00+00:00,34.98
+2020-08-19 15:00:00+00:00,42.04
+2020-08-19 16:00:00+00:00,46.94
+2020-08-19 17:00:00+00:00,53.58
+2020-08-19 18:00:00+00:00,47.16
+2020-08-19 19:00:00+00:00,41.26
+2020-08-19 20:00:00+00:00,39.79
+2020-08-19 21:00:00+00:00,32.93
+2020-08-19 22:00:00+00:00,33.1
+2020-08-19 23:00:00+00:00,28.6
+2020-08-20 00:00:00+00:00,26.1
+2020-08-20 01:00:00+00:00,25.01
+2020-08-20 02:00:00+00:00,25.05
+2020-08-20 03:00:00+00:00,28.03
+2020-08-20 04:00:00+00:00,33.27
+2020-08-20 05:00:00+00:00,38.19
+2020-08-20 06:00:00+00:00,39.79
+2020-08-20 07:00:00+00:00,40.49
+2020-08-20 08:00:00+00:00,39.82
+2020-08-20 09:00:00+00:00,38.08
+2020-08-20 10:00:00+00:00,37.21
+2020-08-20 11:00:00+00:00,34.62
+2020-08-20 12:00:00+00:00,33.87
+2020-08-20 13:00:00+00:00,35.96
+2020-08-20 14:00:00+00:00,36.84
+2020-08-20 15:00:00+00:00,43.34
+2020-08-20 16:00:00+00:00,50.82
+2020-08-20 17:00:00+00:00,63.37
+2020-08-20 18:00:00+00:00,56.51
+2020-08-20 19:00:00+00:00,47.68
+2020-08-20 20:00:00+00:00,42.23
+2020-08-20 21:00:00+00:00,36.58
+2020-08-20 22:00:00+00:00,34.35
+2020-08-20 23:00:00+00:00,28.45
+2020-08-21 00:00:00+00:00,24.15
+2020-08-21 01:00:00+00:00,23.12
+2020-08-21 02:00:00+00:00,20.97
+2020-08-21 03:00:00+00:00,23.09
+2020-08-21 04:00:00+00:00,28.16
+2020-08-21 05:00:00+00:00,35.68
+2020-08-21 06:00:00+00:00,38.98
+2020-08-21 07:00:00+00:00,38.0
+2020-08-21 08:00:00+00:00,33.9
+2020-08-21 09:00:00+00:00,28.75
+2020-08-21 10:00:00+00:00,26.52
+2020-08-21 11:00:00+00:00,26.02
+2020-08-21 12:00:00+00:00,25.26
+2020-08-21 13:00:00+00:00,25.47
+2020-08-21 14:00:00+00:00,28.3
+2020-08-21 15:00:00+00:00,33.9
+2020-08-21 16:00:00+00:00,38.73
+2020-08-21 17:00:00+00:00,41.2
+2020-08-21 18:00:00+00:00,41.6
+2020-08-21 19:00:00+00:00,41.83
+2020-08-21 20:00:00+00:00,40.08
+2020-08-21 21:00:00+00:00,36.91
+2020-08-21 22:00:00+00:00,31.76
+2020-08-21 23:00:00+00:00,26.4
+2020-08-22 00:00:00+00:00,24.08
+2020-08-22 01:00:00+00:00,21.94
+2020-08-22 02:00:00+00:00,21.3
+2020-08-22 03:00:00+00:00,20.3
+2020-08-22 04:00:00+00:00,23.53
+2020-08-22 05:00:00+00:00,25.17
+2020-08-22 06:00:00+00:00,29.91
+2020-08-22 07:00:00+00:00,29.99
+2020-08-22 08:00:00+00:00,27.14
+2020-08-22 09:00:00+00:00,24.31
+2020-08-22 10:00:00+00:00,18.97
+2020-08-22 11:00:00+00:00,11.57
+2020-08-22 12:00:00+00:00,4.25
+2020-08-22 13:00:00+00:00,4.51
+2020-08-22 14:00:00+00:00,14.98
+2020-08-22 15:00:00+00:00,24.62
+2020-08-22 16:00:00+00:00,26.64
+2020-08-22 17:00:00+00:00,30.27
+2020-08-22 18:00:00+00:00,34.43
+2020-08-22 19:00:00+00:00,35.07
+2020-08-22 20:00:00+00:00,33.36
+2020-08-22 21:00:00+00:00,27.4
+2020-08-22 22:00:00+00:00,26.44
+2020-08-22 23:00:00+00:00,24.41
+2020-08-23 00:00:00+00:00,22.14
+2020-08-23 01:00:00+00:00,19.32
+2020-08-23 02:00:00+00:00,14.91
+2020-08-23 03:00:00+00:00,11.84
+2020-08-23 04:00:00+00:00,13.87
+2020-08-23 05:00:00+00:00,19.2
+2020-08-23 06:00:00+00:00,22.19
+2020-08-23 07:00:00+00:00,17.09
+2020-08-23 08:00:00+00:00,4.44
+2020-08-23 09:00:00+00:00,0.6
+2020-08-23 10:00:00+00:00,0.03
+2020-08-23 11:00:00+00:00,-16.18
+2020-08-23 12:00:00+00:00,-12.11
+2020-08-23 13:00:00+00:00,-3.81
+2020-08-23 14:00:00+00:00,0.09
+2020-08-23 15:00:00+00:00,19.7
+2020-08-23 16:00:00+00:00,28.0
+2020-08-23 17:00:00+00:00,33.41
+2020-08-23 18:00:00+00:00,37.32
+2020-08-23 19:00:00+00:00,38.87
+2020-08-23 20:00:00+00:00,38.07
+2020-08-23 21:00:00+00:00,31.99
+2020-08-23 22:00:00+00:00,28.73
+2020-08-23 23:00:00+00:00,27.95
+2020-08-24 00:00:00+00:00,27.14
+2020-08-24 01:00:00+00:00,25.5
+2020-08-24 02:00:00+00:00,25.5
+2020-08-24 03:00:00+00:00,28.9
+2020-08-24 04:00:00+00:00,39.79
+2020-08-24 05:00:00+00:00,53.26
+2020-08-24 06:00:00+00:00,53.13
+2020-08-24 07:00:00+00:00,53.84
+2020-08-24 08:00:00+00:00,47.1
+2020-08-24 09:00:00+00:00,48.0
+2020-08-24 10:00:00+00:00,44.01
+2020-08-24 11:00:00+00:00,42.31
+2020-08-24 12:00:00+00:00,42.1
+2020-08-24 13:00:00+00:00,41.2
+2020-08-24 14:00:00+00:00,41.92
+2020-08-24 15:00:00+00:00,50.25
+2020-08-24 16:00:00+00:00,55.87
+2020-08-24 17:00:00+00:00,66.33
+2020-08-24 18:00:00+00:00,70.16
+2020-08-24 19:00:00+00:00,61.44
+2020-08-24 20:00:00+00:00,54.9
+2020-08-24 21:00:00+00:00,43.97
+2020-08-24 22:00:00+00:00,42.16
+2020-08-24 23:00:00+00:00,37.96
+2020-08-25 00:00:00+00:00,34.48
+2020-08-25 01:00:00+00:00,32.76
+2020-08-25 02:00:00+00:00,32.68
+2020-08-25 03:00:00+00:00,34.7
+2020-08-25 04:00:00+00:00,46.9
+2020-08-25 05:00:00+00:00,48.06
+2020-08-25 06:00:00+00:00,53.66
+2020-08-25 07:00:00+00:00,45.24
+2020-08-25 08:00:00+00:00,43.07
+2020-08-25 09:00:00+00:00,41.69
+2020-08-25 10:00:00+00:00,40.07
+2020-08-25 11:00:00+00:00,37.85
+2020-08-25 12:00:00+00:00,35.6
+2020-08-25 13:00:00+00:00,35.25
+2020-08-25 14:00:00+00:00,35.65
+2020-08-25 15:00:00+00:00,38.95
+2020-08-25 16:00:00+00:00,40.99
+2020-08-25 17:00:00+00:00,42.04
+2020-08-25 18:00:00+00:00,38.03
+2020-08-25 19:00:00+00:00,35.19
+2020-08-25 20:00:00+00:00,30.05
+2020-08-25 21:00:00+00:00,20.07
+2020-08-25 22:00:00+00:00,11.16
+2020-08-25 23:00:00+00:00,3.55
+2020-08-26 00:00:00+00:00,2.78
+2020-08-26 01:00:00+00:00,2.47
+2020-08-26 02:00:00+00:00,2.94
+2020-08-26 03:00:00+00:00,16.94
+2020-08-26 04:00:00+00:00,31.09
+2020-08-26 05:00:00+00:00,37.09
+2020-08-26 06:00:00+00:00,37.81
+2020-08-26 07:00:00+00:00,34.79
+2020-08-26 08:00:00+00:00,21.7
+2020-08-26 09:00:00+00:00,19.07
+2020-08-26 10:00:00+00:00,13.95
+2020-08-26 11:00:00+00:00,8.21
+2020-08-26 12:00:00+00:00,0.31
+2020-08-26 13:00:00+00:00,-3.82
+2020-08-26 14:00:00+00:00,0.49
+2020-08-26 15:00:00+00:00,16.05
+2020-08-26 16:00:00+00:00,29.46
+2020-08-26 17:00:00+00:00,32.0
+2020-08-26 18:00:00+00:00,32.32
+2020-08-26 19:00:00+00:00,30.07
+2020-08-26 20:00:00+00:00,27.49
+2020-08-26 21:00:00+00:00,21.44
+2020-08-26 22:00:00+00:00,19.78
+2020-08-26 23:00:00+00:00,19.6
+2020-08-27 00:00:00+00:00,20.97
+2020-08-27 01:00:00+00:00,23.57
+2020-08-27 02:00:00+00:00,26.05
+2020-08-27 03:00:00+00:00,29.58
+2020-08-27 04:00:00+00:00,42.93
+2020-08-27 05:00:00+00:00,47.78
+2020-08-27 06:00:00+00:00,51.92
+2020-08-27 07:00:00+00:00,40.21
+2020-08-27 08:00:00+00:00,38.41
+2020-08-27 09:00:00+00:00,40.99
+2020-08-27 10:00:00+00:00,43.04
+2020-08-27 11:00:00+00:00,43.83
+2020-08-27 12:00:00+00:00,45.01
+2020-08-27 13:00:00+00:00,46.91
+2020-08-27 14:00:00+00:00,47.87
+2020-08-27 15:00:00+00:00,59.59
+2020-08-27 16:00:00+00:00,70.39
+2020-08-27 17:00:00+00:00,89.91
+2020-08-27 18:00:00+00:00,90.0
+2020-08-27 19:00:00+00:00,69.0
+2020-08-27 20:00:00+00:00,57.9
+2020-08-27 21:00:00+00:00,46.13
+2020-08-27 22:00:00+00:00,39.9
+2020-08-27 23:00:00+00:00,32.75
+2020-08-28 00:00:00+00:00,30.7
+2020-08-28 01:00:00+00:00,29.17
+2020-08-28 02:00:00+00:00,30.43
+2020-08-28 03:00:00+00:00,32.69
+2020-08-28 04:00:00+00:00,40.83
+2020-08-28 05:00:00+00:00,45.71
+2020-08-28 06:00:00+00:00,47.9
+2020-08-28 07:00:00+00:00,48.34
+2020-08-28 08:00:00+00:00,46.49
+2020-08-28 09:00:00+00:00,43.68
+2020-08-28 10:00:00+00:00,37.0
+2020-08-28 11:00:00+00:00,34.63
+2020-08-28 12:00:00+00:00,36.37
+2020-08-28 13:00:00+00:00,38.25
+2020-08-28 14:00:00+00:00,38.25
+2020-08-28 15:00:00+00:00,45.08
+2020-08-28 16:00:00+00:00,47.98
+2020-08-28 17:00:00+00:00,52.11
+2020-08-28 18:00:00+00:00,50.35
+2020-08-28 19:00:00+00:00,46.66
+2020-08-28 20:00:00+00:00,42.36
+2020-08-28 21:00:00+00:00,39.19
+2020-08-28 22:00:00+00:00,36.82
+2020-08-28 23:00:00+00:00,33.76
+2020-08-29 00:00:00+00:00,30.74
+2020-08-29 01:00:00+00:00,29.27
+2020-08-29 02:00:00+00:00,28.31
+2020-08-29 03:00:00+00:00,29.0
+2020-08-29 04:00:00+00:00,29.6
+2020-08-29 05:00:00+00:00,31.76
+2020-08-29 06:00:00+00:00,35.94
+2020-08-29 07:00:00+00:00,38.3
+2020-08-29 08:00:00+00:00,36.84
+2020-08-29 09:00:00+00:00,35.85
+2020-08-29 10:00:00+00:00,30.99
+2020-08-29 11:00:00+00:00,30.29
+2020-08-29 12:00:00+00:00,30.0
+2020-08-29 13:00:00+00:00,31.67
+2020-08-29 14:00:00+00:00,34.71
+2020-08-29 15:00:00+00:00,37.0
+2020-08-29 16:00:00+00:00,43.98
+2020-08-29 17:00:00+00:00,46.39
+2020-08-29 18:00:00+00:00,46.91
+2020-08-29 19:00:00+00:00,44.99
+2020-08-29 20:00:00+00:00,43.0
+2020-08-29 21:00:00+00:00,39.26
+2020-08-29 22:00:00+00:00,38.2
+2020-08-29 23:00:00+00:00,34.98
+2020-08-30 00:00:00+00:00,32.08
+2020-08-30 01:00:00+00:00,31.34
+2020-08-30 02:00:00+00:00,30.74
+2020-08-30 03:00:00+00:00,30.98
+2020-08-30 04:00:00+00:00,30.59
+2020-08-30 05:00:00+00:00,30.74
+2020-08-30 06:00:00+00:00,31.97
+2020-08-30 07:00:00+00:00,32.25
+2020-08-30 08:00:00+00:00,32.39
+2020-08-30 09:00:00+00:00,32.79
+2020-08-30 10:00:00+00:00,31.99
+2020-08-30 11:00:00+00:00,30.98
+2020-08-30 12:00:00+00:00,29.97
+2020-08-30 13:00:00+00:00,29.23
+2020-08-30 14:00:00+00:00,29.98
+2020-08-30 15:00:00+00:00,31.41
+2020-08-30 16:00:00+00:00,35.18
+2020-08-30 17:00:00+00:00,39.08
+2020-08-30 18:00:00+00:00,42.7
+2020-08-30 19:00:00+00:00,43.13
+2020-08-30 20:00:00+00:00,41.97
+2020-08-30 21:00:00+00:00,37.0
+2020-08-30 22:00:00+00:00,29.76
+2020-08-30 23:00:00+00:00,27.92
+2020-08-31 00:00:00+00:00,28.89
+2020-08-31 01:00:00+00:00,28.43
+2020-08-31 02:00:00+00:00,29.41
+2020-08-31 03:00:00+00:00,34.39
+2020-08-31 04:00:00+00:00,45.24
+2020-08-31 05:00:00+00:00,59.94
+2020-08-31 06:00:00+00:00,67.25
+2020-08-31 07:00:00+00:00,68.84
+2020-08-31 08:00:00+00:00,66.53
+2020-08-31 09:00:00+00:00,65.41
+2020-08-31 10:00:00+00:00,62.76
+2020-08-31 11:00:00+00:00,60.0
+2020-08-31 12:00:00+00:00,57.48
+2020-08-31 13:00:00+00:00,54.99
+2020-08-31 14:00:00+00:00,58.95
+2020-08-31 15:00:00+00:00,65.49
+2020-08-31 16:00:00+00:00,71.6
+2020-08-31 17:00:00+00:00,79.06
+2020-08-31 18:00:00+00:00,72.66
+2020-08-31 19:00:00+00:00,64.86
+2020-08-31 20:00:00+00:00,52.02
+2020-08-31 21:00:00+00:00,45.0
+2020-08-31 22:00:00+00:00,39.2
+2020-08-31 23:00:00+00:00,37.91
+2020-09-01 00:00:00+00:00,35.93
+2020-09-01 01:00:00+00:00,34.91
+2020-09-01 02:00:00+00:00,35.89
+2020-09-01 03:00:00+00:00,38.33
+2020-09-01 04:00:00+00:00,48.08
+2020-09-01 05:00:00+00:00,59.0
+2020-09-01 06:00:00+00:00,65.26
+2020-09-01 07:00:00+00:00,59.96
+2020-09-01 08:00:00+00:00,55.36
+2020-09-01 09:00:00+00:00,53.92
+2020-09-01 10:00:00+00:00,50.86
+2020-09-01 11:00:00+00:00,49.77
+2020-09-01 12:00:00+00:00,47.12
+2020-09-01 13:00:00+00:00,47.0
+2020-09-01 14:00:00+00:00,48.58
+2020-09-01 15:00:00+00:00,51.84
+2020-09-01 16:00:00+00:00,60.0
+2020-09-01 17:00:00+00:00,67.02
+2020-09-01 18:00:00+00:00,65.93
+2020-09-01 19:00:00+00:00,55.32
+2020-09-01 20:00:00+00:00,46.95
+2020-09-01 21:00:00+00:00,41.28
+2020-09-01 22:00:00+00:00,41.67
+2020-09-01 23:00:00+00:00,38.02
+2020-09-02 00:00:00+00:00,36.35
+2020-09-02 01:00:00+00:00,34.72
+2020-09-02 02:00:00+00:00,35.7
+2020-09-02 03:00:00+00:00,38.35
+2020-09-02 04:00:00+00:00,50.13
+2020-09-02 05:00:00+00:00,62.23
+2020-09-02 06:00:00+00:00,71.11
+2020-09-02 07:00:00+00:00,63.51
+2020-09-02 08:00:00+00:00,54.51
+2020-09-02 09:00:00+00:00,49.5
+2020-09-02 10:00:00+00:00,44.93
+2020-09-02 11:00:00+00:00,44.11
+2020-09-02 12:00:00+00:00,43.96
+2020-09-02 13:00:00+00:00,44.02
+2020-09-02 14:00:00+00:00,46.46
+2020-09-02 15:00:00+00:00,52.35
+2020-09-02 16:00:00+00:00,60.4
+2020-09-02 17:00:00+00:00,68.89
+2020-09-02 18:00:00+00:00,66.05
+2020-09-02 19:00:00+00:00,55.46
+2020-09-02 20:00:00+00:00,49.34
+2020-09-02 21:00:00+00:00,43.94
+2020-09-02 22:00:00+00:00,44.55
+2020-09-02 23:00:00+00:00,39.04
+2020-09-03 00:00:00+00:00,36.22
+2020-09-03 01:00:00+00:00,34.84
+2020-09-03 02:00:00+00:00,35.43
+2020-09-03 03:00:00+00:00,37.69
+2020-09-03 04:00:00+00:00,49.5
+2020-09-03 05:00:00+00:00,55.98
+2020-09-03 06:00:00+00:00,58.52
+2020-09-03 07:00:00+00:00,52.35
+2020-09-03 08:00:00+00:00,48.17
+2020-09-03 09:00:00+00:00,41.12
+2020-09-03 10:00:00+00:00,30.95
+2020-09-03 11:00:00+00:00,30.36
+2020-09-03 12:00:00+00:00,30.47
+2020-09-03 13:00:00+00:00,34.19
+2020-09-03 14:00:00+00:00,31.11
+2020-09-03 15:00:00+00:00,42.34
+2020-09-03 16:00:00+00:00,47.49
+2020-09-03 17:00:00+00:00,47.74
+2020-09-03 18:00:00+00:00,46.41
+2020-09-03 19:00:00+00:00,41.06
+2020-09-03 20:00:00+00:00,30.84
+2020-09-03 21:00:00+00:00,26.49
+2020-09-03 22:00:00+00:00,26.83
+2020-09-03 23:00:00+00:00,25.71
+2020-09-04 00:00:00+00:00,26.1
+2020-09-04 01:00:00+00:00,25.96
+2020-09-04 02:00:00+00:00,28.0
+2020-09-04 03:00:00+00:00,30.44
+2020-09-04 04:00:00+00:00,39.97
+2020-09-04 05:00:00+00:00,48.43
+2020-09-04 06:00:00+00:00,51.67
+2020-09-04 07:00:00+00:00,49.71
+2020-09-04 08:00:00+00:00,42.03
+2020-09-04 09:00:00+00:00,39.15
+2020-09-04 10:00:00+00:00,36.0
+2020-09-04 11:00:00+00:00,32.67
+2020-09-04 12:00:00+00:00,31.09
+2020-09-04 13:00:00+00:00,31.25
+2020-09-04 14:00:00+00:00,36.48
+2020-09-04 15:00:00+00:00,44.03
+2020-09-04 16:00:00+00:00,47.95
+2020-09-04 17:00:00+00:00,51.43
+2020-09-04 18:00:00+00:00,51.61
+2020-09-04 19:00:00+00:00,45.99
+2020-09-04 20:00:00+00:00,42.79
+2020-09-04 21:00:00+00:00,34.48
+2020-09-04 22:00:00+00:00,39.58
+2020-09-04 23:00:00+00:00,35.34
+2020-09-05 00:00:00+00:00,30.98
+2020-09-05 01:00:00+00:00,29.01
+2020-09-05 02:00:00+00:00,30.06
+2020-09-05 03:00:00+00:00,30.06
+2020-09-05 04:00:00+00:00,31.6
+2020-09-05 05:00:00+00:00,34.2
+2020-09-05 06:00:00+00:00,38.3
+2020-09-05 07:00:00+00:00,37.55
+2020-09-05 08:00:00+00:00,32.26
+2020-09-05 09:00:00+00:00,29.04
+2020-09-05 10:00:00+00:00,28.49
+2020-09-05 11:00:00+00:00,22.91
+2020-09-05 12:00:00+00:00,15.3
+2020-09-05 13:00:00+00:00,26.75
+2020-09-05 14:00:00+00:00,30.04
+2020-09-05 15:00:00+00:00,32.62
+2020-09-05 16:00:00+00:00,38.21
+2020-09-05 17:00:00+00:00,44.04
+2020-09-05 18:00:00+00:00,46.84
+2020-09-05 19:00:00+00:00,43.08
+2020-09-05 20:00:00+00:00,38.94
+2020-09-05 21:00:00+00:00,36.74
+2020-09-05 22:00:00+00:00,34.04
+2020-09-05 23:00:00+00:00,31.0
+2020-09-06 00:00:00+00:00,30.45
+2020-09-06 01:00:00+00:00,29.39
+2020-09-06 02:00:00+00:00,29.39
+2020-09-06 03:00:00+00:00,29.6
+2020-09-06 04:00:00+00:00,30.8
+2020-09-06 05:00:00+00:00,30.9
+2020-09-06 06:00:00+00:00,30.8
+2020-09-06 07:00:00+00:00,33.2
+2020-09-06 08:00:00+00:00,32.19
+2020-09-06 09:00:00+00:00,34.27
+2020-09-06 10:00:00+00:00,34.1
+2020-09-06 11:00:00+00:00,30.7
+2020-09-06 12:00:00+00:00,30.28
+2020-09-06 13:00:00+00:00,30.73
+2020-09-06 14:00:00+00:00,32.4
+2020-09-06 15:00:00+00:00,35.1
+2020-09-06 16:00:00+00:00,42.01
+2020-09-06 17:00:00+00:00,47.19
+2020-09-06 18:00:00+00:00,49.44
+2020-09-06 19:00:00+00:00,46.75
+2020-09-06 20:00:00+00:00,43.88
+2020-09-06 21:00:00+00:00,37.42
+2020-09-06 22:00:00+00:00,34.36
+2020-09-06 23:00:00+00:00,31.07
+2020-09-07 00:00:00+00:00,30.9
+2020-09-07 01:00:00+00:00,30.53
+2020-09-07 02:00:00+00:00,30.58
+2020-09-07 03:00:00+00:00,33.32
+2020-09-07 04:00:00+00:00,47.13
+2020-09-07 05:00:00+00:00,58.44
+2020-09-07 06:00:00+00:00,65.05
+2020-09-07 07:00:00+00:00,55.8
+2020-09-07 08:00:00+00:00,47.97
+2020-09-07 09:00:00+00:00,46.17
+2020-09-07 10:00:00+00:00,42.36
+2020-09-07 11:00:00+00:00,37.78
+2020-09-07 12:00:00+00:00,36.4
+2020-09-07 13:00:00+00:00,37.83
+2020-09-07 14:00:00+00:00,40.14
+2020-09-07 15:00:00+00:00,46.93
+2020-09-07 16:00:00+00:00,54.78
+2020-09-07 17:00:00+00:00,62.37
+2020-09-07 18:00:00+00:00,59.03
+2020-09-07 19:00:00+00:00,46.01
+2020-09-07 20:00:00+00:00,37.78
+2020-09-07 21:00:00+00:00,32.24
+2020-09-07 22:00:00+00:00,30.0
+2020-09-07 23:00:00+00:00,28.63
+2020-09-08 00:00:00+00:00,26.26
+2020-09-08 01:00:00+00:00,25.15
+2020-09-08 02:00:00+00:00,26.25
+2020-09-08 03:00:00+00:00,29.15
+2020-09-08 04:00:00+00:00,31.39
+2020-09-08 05:00:00+00:00,42.7
+2020-09-08 06:00:00+00:00,44.14
+2020-09-08 07:00:00+00:00,35.54
+2020-09-08 08:00:00+00:00,31.65
+2020-09-08 09:00:00+00:00,29.63
+2020-09-08 10:00:00+00:00,27.7
+2020-09-08 11:00:00+00:00,28.0
+2020-09-08 12:00:00+00:00,27.74
+2020-09-08 13:00:00+00:00,32.22
+2020-09-08 14:00:00+00:00,36.88
+2020-09-08 15:00:00+00:00,48.91
+2020-09-08 16:00:00+00:00,55.8
+2020-09-08 17:00:00+00:00,68.37
+2020-09-08 18:00:00+00:00,66.29
+2020-09-08 19:00:00+00:00,49.52
+2020-09-08 20:00:00+00:00,43.73
+2020-09-08 21:00:00+00:00,36.71
+2020-09-08 22:00:00+00:00,32.38
+2020-09-08 23:00:00+00:00,32.92
+2020-09-09 00:00:00+00:00,30.35
+2020-09-09 01:00:00+00:00,29.58
+2020-09-09 02:00:00+00:00,30.12
+2020-09-09 03:00:00+00:00,32.94
+2020-09-09 04:00:00+00:00,46.01
+2020-09-09 05:00:00+00:00,49.13
+2020-09-09 06:00:00+00:00,49.34
+2020-09-09 07:00:00+00:00,43.93
+2020-09-09 08:00:00+00:00,33.08
+2020-09-09 09:00:00+00:00,29.61
+2020-09-09 10:00:00+00:00,29.09
+2020-09-09 11:00:00+00:00,29.07
+2020-09-09 12:00:00+00:00,29.21
+2020-09-09 13:00:00+00:00,29.17
+2020-09-09 14:00:00+00:00,31.16
+2020-09-09 15:00:00+00:00,43.38
+2020-09-09 16:00:00+00:00,47.92
+2020-09-09 17:00:00+00:00,48.03
+2020-09-09 18:00:00+00:00,47.98
+2020-09-09 19:00:00+00:00,43.19
+2020-09-09 20:00:00+00:00,31.99
+2020-09-09 21:00:00+00:00,29.52
+2020-09-09 22:00:00+00:00,28.98
+2020-09-09 23:00:00+00:00,28.97
+2020-09-10 00:00:00+00:00,29.24
+2020-09-10 01:00:00+00:00,29.28
+2020-09-10 02:00:00+00:00,29.2
+2020-09-10 03:00:00+00:00,33.32
+2020-09-10 04:00:00+00:00,45.18
+2020-09-10 05:00:00+00:00,52.78
+2020-09-10 06:00:00+00:00,59.26
+2020-09-10 07:00:00+00:00,52.74
+2020-09-10 08:00:00+00:00,48.5
+2020-09-10 09:00:00+00:00,47.21
+2020-09-10 10:00:00+00:00,46.08
+2020-09-10 11:00:00+00:00,44.01
+2020-09-10 12:00:00+00:00,42.45
+2020-09-10 13:00:00+00:00,44.73
+2020-09-10 14:00:00+00:00,48.08
+2020-09-10 15:00:00+00:00,55.74
+2020-09-10 16:00:00+00:00,65.81
+2020-09-10 17:00:00+00:00,78.01
+2020-09-10 18:00:00+00:00,75.23
+2020-09-10 19:00:00+00:00,57.43
+2020-09-10 20:00:00+00:00,49.89
+2020-09-10 21:00:00+00:00,43.98
+2020-09-10 22:00:00+00:00,45.84
+2020-09-10 23:00:00+00:00,40.0
+2020-09-11 00:00:00+00:00,39.38
+2020-09-11 01:00:00+00:00,36.79
+2020-09-11 02:00:00+00:00,36.85
+2020-09-11 03:00:00+00:00,41.12
+2020-09-11 04:00:00+00:00,53.91
+2020-09-11 05:00:00+00:00,62.57
+2020-09-11 06:00:00+00:00,69.45
+2020-09-11 07:00:00+00:00,62.0
+2020-09-11 08:00:00+00:00,49.94
+2020-09-11 09:00:00+00:00,46.02
+2020-09-11 10:00:00+00:00,40.79
+2020-09-11 11:00:00+00:00,36.47
+2020-09-11 12:00:00+00:00,34.05
+2020-09-11 13:00:00+00:00,35.06
+2020-09-11 14:00:00+00:00,40.42
+2020-09-11 15:00:00+00:00,48.01
+2020-09-11 16:00:00+00:00,55.4
+2020-09-11 17:00:00+00:00,64.21
+2020-09-11 18:00:00+00:00,62.6
+2020-09-11 19:00:00+00:00,52.05
+2020-09-11 20:00:00+00:00,49.83
+2020-09-11 21:00:00+00:00,44.78
+2020-09-11 22:00:00+00:00,42.91
+2020-09-11 23:00:00+00:00,37.27
+2020-09-12 00:00:00+00:00,34.33
+2020-09-12 01:00:00+00:00,34.16
+2020-09-12 02:00:00+00:00,32.37
+2020-09-12 03:00:00+00:00,33.05
+2020-09-12 04:00:00+00:00,36.43
+2020-09-12 05:00:00+00:00,39.46
+2020-09-12 06:00:00+00:00,38.31
+2020-09-12 07:00:00+00:00,36.8
+2020-09-12 08:00:00+00:00,30.78
+2020-09-12 09:00:00+00:00,28.04
+2020-09-12 10:00:00+00:00,2.75
+2020-09-12 11:00:00+00:00,-0.12
+2020-09-12 12:00:00+00:00,-0.45
+2020-09-12 13:00:00+00:00,4.55
+2020-09-12 14:00:00+00:00,27.54
+2020-09-12 15:00:00+00:00,34.56
+2020-09-12 16:00:00+00:00,44.9
+2020-09-12 17:00:00+00:00,49.02
+2020-09-12 18:00:00+00:00,49.98
+2020-09-12 19:00:00+00:00,47.06
+2020-09-12 20:00:00+00:00,43.0
+2020-09-12 21:00:00+00:00,38.22
+2020-09-12 22:00:00+00:00,35.46
+2020-09-12 23:00:00+00:00,33.31
+2020-09-13 00:00:00+00:00,31.25
+2020-09-13 01:00:00+00:00,30.03
+2020-09-13 02:00:00+00:00,27.87
+2020-09-13 03:00:00+00:00,26.97
+2020-09-13 04:00:00+00:00,29.14
+2020-09-13 05:00:00+00:00,29.74
+2020-09-13 06:00:00+00:00,30.13
+2020-09-13 07:00:00+00:00,30.23
+2020-09-13 08:00:00+00:00,15.07
+2020-09-13 09:00:00+00:00,0.01
+2020-09-13 10:00:00+00:00,-24.08
+2020-09-13 11:00:00+00:00,-58.8
+2020-09-13 12:00:00+00:00,-49.94
+2020-09-13 13:00:00+00:00,-12.9
+2020-09-13 14:00:00+00:00,10.69
+2020-09-13 15:00:00+00:00,34.2
+2020-09-13 16:00:00+00:00,40.0
+2020-09-13 17:00:00+00:00,48.6
+2020-09-13 18:00:00+00:00,50.92
+2020-09-13 19:00:00+00:00,48.08
+2020-09-13 20:00:00+00:00,43.5
+2020-09-13 21:00:00+00:00,35.06
+2020-09-13 22:00:00+00:00,35.22
+2020-09-13 23:00:00+00:00,34.28
+2020-09-14 00:00:00+00:00,32.9
+2020-09-14 01:00:00+00:00,32.35
+2020-09-14 02:00:00+00:00,32.32
+2020-09-14 03:00:00+00:00,36.07
+2020-09-14 04:00:00+00:00,50.0
+2020-09-14 05:00:00+00:00,58.34
+2020-09-14 06:00:00+00:00,62.05
+2020-09-14 07:00:00+00:00,55.93
+2020-09-14 08:00:00+00:00,50.49
+2020-09-14 09:00:00+00:00,46.04
+2020-09-14 10:00:00+00:00,40.46
+2020-09-14 11:00:00+00:00,42.28
+2020-09-14 12:00:00+00:00,40.15
+2020-09-14 13:00:00+00:00,45.23
+2020-09-14 14:00:00+00:00,51.69
+2020-09-14 15:00:00+00:00,66.4
+2020-09-14 16:00:00+00:00,80.98
+2020-09-14 17:00:00+00:00,120.62
+2020-09-14 18:00:00+00:00,96.43
+2020-09-14 19:00:00+00:00,66.32
+2020-09-14 20:00:00+00:00,54.01
+2020-09-14 21:00:00+00:00,44.15
+2020-09-14 22:00:00+00:00,41.23
+2020-09-14 23:00:00+00:00,40.81
+2020-09-15 00:00:00+00:00,39.2
+2020-09-15 01:00:00+00:00,37.77
+2020-09-15 02:00:00+00:00,38.6
+2020-09-15 03:00:00+00:00,41.81
+2020-09-15 04:00:00+00:00,53.9
+2020-09-15 05:00:00+00:00,74.84
+2020-09-15 06:00:00+00:00,84.35
+2020-09-15 07:00:00+00:00,77.64
+2020-09-15 08:00:00+00:00,67.29
+2020-09-15 09:00:00+00:00,61.37
+2020-09-15 10:00:00+00:00,49.95
+2020-09-15 11:00:00+00:00,50.01
+2020-09-15 12:00:00+00:00,52.71
+2020-09-15 13:00:00+00:00,59.9
+2020-09-15 14:00:00+00:00,70.01
+2020-09-15 15:00:00+00:00,82.71
+2020-09-15 16:00:00+00:00,130.59
+2020-09-15 17:00:00+00:00,189.25
+2020-09-15 18:00:00+00:00,148.18
+2020-09-15 19:00:00+00:00,77.68
+2020-09-15 20:00:00+00:00,63.44
+2020-09-15 21:00:00+00:00,51.51
+2020-09-15 22:00:00+00:00,50.12
+2020-09-15 23:00:00+00:00,46.3
+2020-09-16 00:00:00+00:00,45.1
+2020-09-16 01:00:00+00:00,43.12
+2020-09-16 02:00:00+00:00,44.0
+2020-09-16 03:00:00+00:00,46.35
+2020-09-16 04:00:00+00:00,59.98
+2020-09-16 05:00:00+00:00,76.39
+2020-09-16 06:00:00+00:00,86.53
+2020-09-16 07:00:00+00:00,75.0
+2020-09-16 08:00:00+00:00,63.32
+2020-09-16 09:00:00+00:00,56.96
+2020-09-16 10:00:00+00:00,48.35
+2020-09-16 11:00:00+00:00,43.29
+2020-09-16 12:00:00+00:00,39.98
+2020-09-16 13:00:00+00:00,43.16
+2020-09-16 14:00:00+00:00,45.07
+2020-09-16 15:00:00+00:00,54.8
+2020-09-16 16:00:00+00:00,61.48
+2020-09-16 17:00:00+00:00,66.45
+2020-09-16 18:00:00+00:00,57.44
+2020-09-16 19:00:00+00:00,48.39
+2020-09-16 20:00:00+00:00,43.37
+2020-09-16 21:00:00+00:00,36.96
+2020-09-16 22:00:00+00:00,34.11
+2020-09-16 23:00:00+00:00,34.85
+2020-09-17 00:00:00+00:00,34.73
+2020-09-17 01:00:00+00:00,34.32
+2020-09-17 02:00:00+00:00,34.58
+2020-09-17 03:00:00+00:00,36.56
+2020-09-17 04:00:00+00:00,48.0
+2020-09-17 05:00:00+00:00,53.64
+2020-09-17 06:00:00+00:00,59.69
+2020-09-17 07:00:00+00:00,53.91
+2020-09-17 08:00:00+00:00,45.8
+2020-09-17 09:00:00+00:00,42.0
+2020-09-17 10:00:00+00:00,39.89
+2020-09-17 11:00:00+00:00,39.07
+2020-09-17 12:00:00+00:00,37.1
+2020-09-17 13:00:00+00:00,36.66
+2020-09-17 14:00:00+00:00,47.74
+2020-09-17 15:00:00+00:00,56.43
+2020-09-17 16:00:00+00:00,66.5
+2020-09-17 17:00:00+00:00,79.84
+2020-09-17 18:00:00+00:00,65.44
+2020-09-17 19:00:00+00:00,53.19
+2020-09-17 20:00:00+00:00,42.68
+2020-09-17 21:00:00+00:00,36.92
+2020-09-17 22:00:00+00:00,37.97
+2020-09-17 23:00:00+00:00,35.06
+2020-09-18 00:00:00+00:00,34.68
+2020-09-18 01:00:00+00:00,34.51
+2020-09-18 02:00:00+00:00,34.2
+2020-09-18 03:00:00+00:00,36.9
+2020-09-18 04:00:00+00:00,45.02
+2020-09-18 05:00:00+00:00,53.02
+2020-09-18 06:00:00+00:00,58.11
+2020-09-18 07:00:00+00:00,52.79
+2020-09-18 08:00:00+00:00,44.67
+2020-09-18 09:00:00+00:00,38.35
+2020-09-18 10:00:00+00:00,34.89
+2020-09-18 11:00:00+00:00,34.51
+2020-09-18 12:00:00+00:00,34.38
+2020-09-18 13:00:00+00:00,35.47
+2020-09-18 14:00:00+00:00,36.7
+2020-09-18 15:00:00+00:00,46.62
+2020-09-18 16:00:00+00:00,53.08
+2020-09-18 17:00:00+00:00,56.22
+2020-09-18 18:00:00+00:00,52.05
+2020-09-18 19:00:00+00:00,46.4
+2020-09-18 20:00:00+00:00,39.41
+2020-09-18 21:00:00+00:00,36.04
+2020-09-18 22:00:00+00:00,33.25
+2020-09-18 23:00:00+00:00,31.08
+2020-09-19 00:00:00+00:00,32.55
+2020-09-19 01:00:00+00:00,31.89
+2020-09-19 02:00:00+00:00,31.26
+2020-09-19 03:00:00+00:00,30.75
+2020-09-19 04:00:00+00:00,34.31
+2020-09-19 05:00:00+00:00,37.02
+2020-09-19 06:00:00+00:00,39.76
+2020-09-19 07:00:00+00:00,36.78
+2020-09-19 08:00:00+00:00,33.58
+2020-09-19 09:00:00+00:00,32.56
+2020-09-19 10:00:00+00:00,31.67
+2020-09-19 11:00:00+00:00,30.73
+2020-09-19 12:00:00+00:00,30.72
+2020-09-19 13:00:00+00:00,32.41
+2020-09-19 14:00:00+00:00,34.99
+2020-09-19 15:00:00+00:00,40.7
+2020-09-19 16:00:00+00:00,47.95
+2020-09-19 17:00:00+00:00,51.02
+2020-09-19 18:00:00+00:00,51.05
+2020-09-19 19:00:00+00:00,44.41
+2020-09-19 20:00:00+00:00,39.74
+2020-09-19 21:00:00+00:00,36.71
+2020-09-19 22:00:00+00:00,37.89
+2020-09-19 23:00:00+00:00,36.77
+2020-09-20 00:00:00+00:00,35.36
+2020-09-20 01:00:00+00:00,34.4
+2020-09-20 02:00:00+00:00,34.21
+2020-09-20 03:00:00+00:00,34.2
+2020-09-20 04:00:00+00:00,34.8
+2020-09-20 05:00:00+00:00,34.5
+2020-09-20 06:00:00+00:00,35.05
+2020-09-20 07:00:00+00:00,36.75
+2020-09-20 08:00:00+00:00,34.2
+2020-09-20 09:00:00+00:00,31.34
+2020-09-20 10:00:00+00:00,31.13
+2020-09-20 11:00:00+00:00,31.02
+2020-09-20 12:00:00+00:00,32.34
+2020-09-20 13:00:00+00:00,32.95
+2020-09-20 14:00:00+00:00,34.2
+2020-09-20 15:00:00+00:00,38.31
+2020-09-20 16:00:00+00:00,46.47
+2020-09-20 17:00:00+00:00,51.7
+2020-09-20 18:00:00+00:00,51.91
+2020-09-20 19:00:00+00:00,47.9
+2020-09-20 20:00:00+00:00,44.65
+2020-09-20 21:00:00+00:00,38.31
+2020-09-20 22:00:00+00:00,37.24
+2020-09-20 23:00:00+00:00,35.46
+2020-09-21 00:00:00+00:00,35.6
+2020-09-21 01:00:00+00:00,35.54
+2020-09-21 02:00:00+00:00,36.07
+2020-09-21 03:00:00+00:00,43.11
+2020-09-21 04:00:00+00:00,54.36
+2020-09-21 05:00:00+00:00,73.19
+2020-09-21 06:00:00+00:00,85.0
+2020-09-21 07:00:00+00:00,72.09
+2020-09-21 08:00:00+00:00,54.4
+2020-09-21 09:00:00+00:00,48.13
+2020-09-21 10:00:00+00:00,44.25
+2020-09-21 11:00:00+00:00,40.98
+2020-09-21 12:00:00+00:00,44.01
+2020-09-21 13:00:00+00:00,50.96
+2020-09-21 14:00:00+00:00,56.0
+2020-09-21 15:00:00+00:00,65.0
+2020-09-21 16:00:00+00:00,90.81
+2020-09-21 17:00:00+00:00,200.04
+2020-09-21 18:00:00+00:00,98.13
+2020-09-21 19:00:00+00:00,62.52
+2020-09-21 20:00:00+00:00,54.67
+2020-09-21 21:00:00+00:00,48.73
+2020-09-21 22:00:00+00:00,42.93
+2020-09-21 23:00:00+00:00,43.17
+2020-09-22 00:00:00+00:00,42.05
+2020-09-22 01:00:00+00:00,40.61
+2020-09-22 02:00:00+00:00,41.03
+2020-09-22 03:00:00+00:00,44.16
+2020-09-22 04:00:00+00:00,52.97
+2020-09-22 05:00:00+00:00,72.89
+2020-09-22 06:00:00+00:00,73.09
+2020-09-22 07:00:00+00:00,61.85
+2020-09-22 08:00:00+00:00,52.05
+2020-09-22 09:00:00+00:00,48.02
+2020-09-22 10:00:00+00:00,44.95
+2020-09-22 11:00:00+00:00,43.26
+2020-09-22 12:00:00+00:00,42.71
+2020-09-22 13:00:00+00:00,48.32
+2020-09-22 14:00:00+00:00,53.93
+2020-09-22 15:00:00+00:00,58.92
+2020-09-22 16:00:00+00:00,70.0
+2020-09-22 17:00:00+00:00,86.4
+2020-09-22 18:00:00+00:00,70.0
+2020-09-22 19:00:00+00:00,55.47
+2020-09-22 20:00:00+00:00,50.19
+2020-09-22 21:00:00+00:00,40.55
+2020-09-22 22:00:00+00:00,43.51
+2020-09-22 23:00:00+00:00,41.08
+2020-09-23 00:00:00+00:00,39.71
+2020-09-23 01:00:00+00:00,38.45
+2020-09-23 02:00:00+00:00,37.12
+2020-09-23 03:00:00+00:00,39.52
+2020-09-23 04:00:00+00:00,51.92
+2020-09-23 05:00:00+00:00,53.21
+2020-09-23 06:00:00+00:00,58.32
+2020-09-23 07:00:00+00:00,52.56
+2020-09-23 08:00:00+00:00,48.94
+2020-09-23 09:00:00+00:00,48.92
+2020-09-23 10:00:00+00:00,43.94
+2020-09-23 11:00:00+00:00,41.33
+2020-09-23 12:00:00+00:00,43.58
+2020-09-23 13:00:00+00:00,43.46
+2020-09-23 14:00:00+00:00,42.18
+2020-09-23 15:00:00+00:00,54.93
+2020-09-23 16:00:00+00:00,56.43
+2020-09-23 17:00:00+00:00,60.8
+2020-09-23 18:00:00+00:00,53.01
+2020-09-23 19:00:00+00:00,49.89
+2020-09-23 20:00:00+00:00,39.02
+2020-09-23 21:00:00+00:00,32.45
+2020-09-23 22:00:00+00:00,29.95
+2020-09-23 23:00:00+00:00,28.44
+2020-09-24 00:00:00+00:00,26.47
+2020-09-24 01:00:00+00:00,22.26
+2020-09-24 02:00:00+00:00,19.08
+2020-09-24 03:00:00+00:00,26.55
+2020-09-24 04:00:00+00:00,39.18
+2020-09-24 05:00:00+00:00,49.97
+2020-09-24 06:00:00+00:00,51.46
+2020-09-24 07:00:00+00:00,36.45
+2020-09-24 08:00:00+00:00,33.01
+2020-09-24 09:00:00+00:00,29.84
+2020-09-24 10:00:00+00:00,31.35
+2020-09-24 11:00:00+00:00,31.42
+2020-09-24 12:00:00+00:00,35.79
+2020-09-24 13:00:00+00:00,37.43
+2020-09-24 14:00:00+00:00,39.76
+2020-09-24 15:00:00+00:00,46.84
+2020-09-24 16:00:00+00:00,53.93
+2020-09-24 17:00:00+00:00,67.57
+2020-09-24 18:00:00+00:00,54.94
+2020-09-24 19:00:00+00:00,47.63
+2020-09-24 20:00:00+00:00,42.01
+2020-09-24 21:00:00+00:00,35.09
+2020-09-24 22:00:00+00:00,33.34
+2020-09-24 23:00:00+00:00,31.92
+2020-09-25 00:00:00+00:00,29.03
+2020-09-25 01:00:00+00:00,27.2
+2020-09-25 02:00:00+00:00,28.26
+2020-09-25 03:00:00+00:00,30.1
+2020-09-25 04:00:00+00:00,41.74
+2020-09-25 05:00:00+00:00,51.93
+2020-09-25 06:00:00+00:00,56.48
+2020-09-25 07:00:00+00:00,52.95
+2020-09-25 08:00:00+00:00,48.17
+2020-09-25 09:00:00+00:00,47.27
+2020-09-25 10:00:00+00:00,46.23
+2020-09-25 11:00:00+00:00,41.07
+2020-09-25 12:00:00+00:00,35.76
+2020-09-25 13:00:00+00:00,34.43
+2020-09-25 14:00:00+00:00,35.1
+2020-09-25 15:00:00+00:00,45.72
+2020-09-25 16:00:00+00:00,50.94
+2020-09-25 17:00:00+00:00,53.1
+2020-09-25 18:00:00+00:00,51.21
+2020-09-25 19:00:00+00:00,46.03
+2020-09-25 20:00:00+00:00,39.82
+2020-09-25 21:00:00+00:00,35.12
+2020-09-25 22:00:00+00:00,34.01
+2020-09-25 23:00:00+00:00,30.71
+2020-09-26 00:00:00+00:00,28.03
+2020-09-26 01:00:00+00:00,26.39
+2020-09-26 02:00:00+00:00,25.94
+2020-09-26 03:00:00+00:00,27.17
+2020-09-26 04:00:00+00:00,28.97
+2020-09-26 05:00:00+00:00,31.98
+2020-09-26 06:00:00+00:00,36.72
+2020-09-26 07:00:00+00:00,41.22
+2020-09-26 08:00:00+00:00,39.4
+2020-09-26 09:00:00+00:00,38.13
+2020-09-26 10:00:00+00:00,34.08
+2020-09-26 11:00:00+00:00,32.03
+2020-09-26 12:00:00+00:00,28.9
+2020-09-26 13:00:00+00:00,27.92
+2020-09-26 14:00:00+00:00,29.18
+2020-09-26 15:00:00+00:00,33.95
+2020-09-26 16:00:00+00:00,39.49
+2020-09-26 17:00:00+00:00,45.49
+2020-09-26 18:00:00+00:00,41.25
+2020-09-26 19:00:00+00:00,34.08
+2020-09-26 20:00:00+00:00,31.76
+2020-09-26 21:00:00+00:00,28.34
+2020-09-26 22:00:00+00:00,0.75
+2020-09-26 23:00:00+00:00,19.92
+2020-09-27 00:00:00+00:00,17.99
+2020-09-27 01:00:00+00:00,12.25
+2020-09-27 02:00:00+00:00,12.0
+2020-09-27 03:00:00+00:00,14.39
+2020-09-27 04:00:00+00:00,17.86
+2020-09-27 05:00:00+00:00,21.7
+2020-09-27 06:00:00+00:00,27.11
+2020-09-27 07:00:00+00:00,32.0
+2020-09-27 08:00:00+00:00,32.99
+2020-09-27 09:00:00+00:00,34.26
+2020-09-27 10:00:00+00:00,35.8
+2020-09-27 11:00:00+00:00,32.4
+2020-09-27 12:00:00+00:00,31.99
+2020-09-27 13:00:00+00:00,32.01
+2020-09-27 14:00:00+00:00,33.32
+2020-09-27 15:00:00+00:00,37.63
+2020-09-27 16:00:00+00:00,46.23
+2020-09-27 17:00:00+00:00,51.95
+2020-09-27 18:00:00+00:00,50.0
+2020-09-27 19:00:00+00:00,46.48
+2020-09-27 20:00:00+00:00,41.76
+2020-09-27 21:00:00+00:00,37.84
+2020-09-27 22:00:00+00:00,33.3
+2020-09-27 23:00:00+00:00,30.82
+2020-09-28 00:00:00+00:00,29.5
+2020-09-28 01:00:00+00:00,28.6
+2020-09-28 02:00:00+00:00,28.72
+2020-09-28 03:00:00+00:00,30.89
+2020-09-28 04:00:00+00:00,47.04
+2020-09-28 05:00:00+00:00,55.64
+2020-09-28 06:00:00+00:00,59.31
+2020-09-28 07:00:00+00:00,56.54
+2020-09-28 08:00:00+00:00,53.0
+2020-09-28 09:00:00+00:00,51.72
+2020-09-28 10:00:00+00:00,49.16
+2020-09-28 11:00:00+00:00,48.0
+2020-09-28 12:00:00+00:00,46.0
+2020-09-28 13:00:00+00:00,47.04
+2020-09-28 14:00:00+00:00,48.46
+2020-09-28 15:00:00+00:00,52.93
+2020-09-28 16:00:00+00:00,61.14
+2020-09-28 17:00:00+00:00,80.03
+2020-09-28 18:00:00+00:00,58.0
+2020-09-28 19:00:00+00:00,52.24
+2020-09-28 20:00:00+00:00,46.16
+2020-09-28 21:00:00+00:00,40.01
+2020-09-28 22:00:00+00:00,37.85
+2020-09-28 23:00:00+00:00,37.43
+2020-09-29 00:00:00+00:00,36.85
+2020-09-29 01:00:00+00:00,34.79
+2020-09-29 02:00:00+00:00,36.48
+2020-09-29 03:00:00+00:00,39.51
+2020-09-29 04:00:00+00:00,51.58
+2020-09-29 05:00:00+00:00,67.87
+2020-09-29 06:00:00+00:00,84.65
+2020-09-29 07:00:00+00:00,76.0
+2020-09-29 08:00:00+00:00,69.4
+2020-09-29 09:00:00+00:00,66.62
+2020-09-29 10:00:00+00:00,59.37
+2020-09-29 11:00:00+00:00,54.25
+2020-09-29 12:00:00+00:00,52.24
+2020-09-29 13:00:00+00:00,53.0
+2020-09-29 14:00:00+00:00,56.95
+2020-09-29 15:00:00+00:00,62.43
+2020-09-29 16:00:00+00:00,73.69
+2020-09-29 17:00:00+00:00,128.31
+2020-09-29 18:00:00+00:00,73.14
+2020-09-29 19:00:00+00:00,57.5
+2020-09-29 20:00:00+00:00,51.57
+2020-09-29 21:00:00+00:00,45.36
+2020-09-29 22:00:00+00:00,41.7
+2020-09-29 23:00:00+00:00,41.78
+2020-09-30 00:00:00+00:00,39.9
+2020-09-30 01:00:00+00:00,37.95
+2020-09-30 02:00:00+00:00,37.79
+2020-09-30 03:00:00+00:00,41.89
+2020-09-30 04:00:00+00:00,51.32
+2020-09-30 05:00:00+00:00,62.37
+2020-09-30 06:00:00+00:00,72.8
+2020-09-30 07:00:00+00:00,65.76
+2020-09-30 08:00:00+00:00,55.16
+2020-09-30 09:00:00+00:00,52.29
+2020-09-30 10:00:00+00:00,49.17
+2020-09-30 11:00:00+00:00,47.4
+2020-09-30 12:00:00+00:00,45.04
+2020-09-30 13:00:00+00:00,45.19
+2020-09-30 14:00:00+00:00,48.94
+2020-09-30 15:00:00+00:00,53.98
+2020-09-30 16:00:00+00:00,60.14
+2020-09-30 17:00:00+00:00,72.43
+2020-09-30 18:00:00+00:00,55.34
+2020-09-30 19:00:00+00:00,49.92
+2020-09-30 20:00:00+00:00,42.79
+2020-09-30 21:00:00+00:00,35.02
+2020-09-30 22:00:00+00:00,34.4
diff --git a/docs/notebooks/data/raw/tmy_dresden.csv b/docs/notebooks/data/raw/tmy_dresden.csv
new file mode 100644
index 000000000..176ef3468
--- /dev/null
+++ b/docs/notebooks/data/raw/tmy_dresden.csv
@@ -0,0 +1,8761 @@
+time,temperature_C,ghi_W_m2,dni_W_m2,dhi_W_m2,wind_speed_m_s,relative_humidity_percent
+2020-01-01 00:00:00,-1.77,0.0,-0.0,0.0,2.87,88.15
+2020-01-01 01:00:00,-2.63,0.0,-0.0,0.0,2.78,88.43
+2020-01-01 02:00:00,-3.49,0.0,-0.0,0.0,2.68,88.71
+2020-01-01 03:00:00,-4.35,0.0,-0.0,0.0,2.59,88.99
+2020-01-01 04:00:00,-5.22,0.0,-0.0,0.0,2.5,89.28
+2020-01-01 05:00:00,-6.08,0.0,-0.0,0.0,2.41,89.56
+2020-01-01 06:00:00,-6.94,0.0,-0.0,0.0,2.31,89.84
+2020-01-01 07:00:00,-7.8,0.0,-0.0,0.0,2.22,90.12
+2020-01-01 08:00:00,-5.5,43.0,36.5,39.0,3.59,88.05
+2020-01-01 09:00:00,-5.19,45.0,0.0,45.0,3.24,81.25
+2020-01-01 10:00:00,-4.84,63.0,0.0,63.0,3.03,84.6
+2020-01-01 11:00:00,-4.41,57.0,0.0,57.0,2.97,81.3
+2020-01-01 12:00:00,-3.98,56.0,0.0,56.0,3.24,78.15
+2020-01-01 13:00:00,-3.74,42.0,0.0,42.0,3.1,78.15
+2020-01-01 14:00:00,-3.65,19.0,0.0,19.0,2.76,78.2
+2020-01-01 15:00:00,-3.63,0.0,-0.0,0.0,3.03,78.2
+2020-01-01 16:00:00,-3.66,0.0,-0.0,0.0,2.62,78.2
+2020-01-01 17:00:00,-3.72,0.0,-0.0,0.0,2.14,84.7
+2020-01-01 18:00:00,-3.7,0.0,-0.0,0.0,2.14,84.7
+2020-01-01 19:00:00,-3.78,0.0,-0.0,0.0,2.0,84.7
+2020-01-01 20:00:00,-3.63,0.0,-0.0,0.0,2.21,84.8
+2020-01-01 21:00:00,-3.62,0.0,-0.0,0.0,1.66,84.8
+2020-01-01 22:00:00,-3.6,0.0,-0.0,0.0,1.59,84.8
+2020-01-01 23:00:00,-3.57,0.0,-0.0,0.0,1.66,84.8
+2020-01-02 00:00:00,-3.55,0.0,-0.0,0.0,1.59,88.25
+2020-01-02 01:00:00,-3.02,0.0,-0.0,0.0,1.38,88.25
+2020-01-02 02:00:00,-2.98,0.0,-0.0,0.0,1.31,88.25
+2020-01-02 03:00:00,-2.98,0.0,-0.0,0.0,1.24,91.85
+2020-01-02 04:00:00,-3.27,0.0,-0.0,0.0,1.1,95.55
+2020-01-02 05:00:00,-3.09,0.0,-0.0,0.0,1.45,91.85
+2020-01-02 06:00:00,-3.08,0.0,-0.0,0.0,1.31,91.85
+2020-01-02 07:00:00,-3.09,0.0,-0.0,0.0,1.17,91.85
+2020-01-02 08:00:00,-3.18,0.0,0.0,0.0,1.24,91.85
+2020-01-02 09:00:00,-2.92,0.0,0.0,0.0,1.59,91.85
+2020-01-02 10:00:00,-2.45,81.0,0.0,81.0,2.0,88.25
+2020-01-02 11:00:00,-1.96,0.0,0.0,0.0,2.41,81.55
+2020-01-02 12:00:00,-1.7,68.0,0.0,68.0,2.55,81.55
+2020-01-02 13:00:00,-1.68,0.0,0.0,0.0,2.62,81.55
+2020-01-02 14:00:00,-1.72,21.0,0.0,21.0,2.55,84.85
+2020-01-02 15:00:00,-2.02,0.0,-0.0,0.0,2.48,88.3
+2020-01-02 16:00:00,-2.52,0.0,-0.0,0.0,2.07,95.55
+2020-01-02 17:00:00,-2.97,0.0,-0.0,0.0,2.14,95.55
+2020-01-02 18:00:00,-3.41,0.0,-0.0,0.0,2.07,95.55
+2020-01-02 19:00:00,-3.9,0.0,-0.0,0.0,1.66,95.5
+2020-01-02 20:00:00,-4.56,0.0,-0.0,0.0,1.31,91.75
+2020-01-02 21:00:00,-5.05,0.0,-0.0,0.0,1.17,95.5
+2020-01-02 22:00:00,-5.45,0.0,-0.0,0.0,1.17,95.45
+2020-01-02 23:00:00,-5.83,0.0,-0.0,0.0,1.17,95.45
+2020-01-03 00:00:00,-6.38,0.0,-0.0,0.0,1.31,95.45
+2020-01-03 01:00:00,-7.02,0.0,-0.0,0.0,1.45,95.45
+2020-01-03 02:00:00,-7.5,0.0,-0.0,0.0,1.59,95.4
+2020-01-03 03:00:00,-7.62,0.0,-0.0,0.0,1.72,91.6
+2020-01-03 04:00:00,-7.48,0.0,-0.0,0.0,1.79,91.6
+2020-01-03 05:00:00,-7.32,0.0,-0.0,0.0,1.93,91.6
+2020-01-03 06:00:00,-7.03,0.0,-0.0,0.0,1.93,91.6
+2020-01-03 07:00:00,-6.78,0.0,-0.0,0.0,2.14,87.95
+2020-01-03 08:00:00,-6.44,70.0,234.63,44.0,2.21,84.45
+2020-01-03 09:00:00,-5.47,0.0,0.0,0.0,2.41,74.8
+2020-01-03 10:00:00,-4.08,205.0,378.45,107.0,2.9,58.6
+2020-01-03 11:00:00,-2.98,0.0,0.0,0.0,3.1,49.8
+2020-01-03 12:00:00,-2.22,197.0,338.72,110.0,3.1,49.8
+2020-01-03 13:00:00,-1.97,0.0,0.0,0.0,3.03,45.9
+2020-01-03 14:00:00,-2.24,59.0,161.79,42.0,2.69,49.8
+2020-01-03 15:00:00,-3.08,0.0,-0.0,0.0,2.76,47.75
+2020-01-03 16:00:00,-3.73,0.0,-0.0,0.0,2.97,51.65
+2020-01-03 17:00:00,-4.02,0.0,-0.0,0.0,3.17,49.55
+2020-01-03 18:00:00,-4.11,0.0,-0.0,0.0,3.45,49.55
+2020-01-03 19:00:00,-4.04,0.0,-0.0,0.0,3.72,63.7
+2020-01-03 20:00:00,-3.78,0.0,-0.0,0.0,3.93,66.35
+2020-01-03 21:00:00,-3.33,0.0,-0.0,0.0,4.14,69.25
+2020-01-03 22:00:00,-2.55,0.0,-0.0,0.0,4.48,72.25
+2020-01-03 23:00:00,-2.05,0.0,-0.0,0.0,4.76,75.3
+2020-01-04 00:00:00,-1.77,0.0,-0.0,0.0,4.83,81.55
+2020-01-04 01:00:00,-1.68,0.0,-0.0,0.0,4.76,84.85
+2020-01-04 02:00:00,-1.5,0.0,-0.0,0.0,4.69,84.95
+2020-01-04 03:00:00,-1.42,0.0,-0.0,0.0,4.55,88.35
+2020-01-04 04:00:00,-1.35,0.0,-0.0,0.0,4.41,88.35
+2020-01-04 05:00:00,-1.35,0.0,-0.0,0.0,4.28,88.35
+2020-01-04 06:00:00,-1.27,0.0,-0.0,0.0,4.07,88.35
+2020-01-04 07:00:00,-0.83,0.0,-0.0,0.0,4.14,91.95
+2020-01-04 08:00:00,-0.65,26.0,0.0,26.0,4.07,88.45
+2020-01-04 09:00:00,-0.36,0.0,0.0,0.0,3.93,88.45
+2020-01-04 10:00:00,-0.19,67.0,0.0,67.0,4.76,91.95
+2020-01-04 11:00:00,-0.08,0.0,0.0,0.0,5.1,88.45
+2020-01-04 12:00:00,-0.16,116.0,34.77,107.0,3.93,91.95
+2020-01-04 13:00:00,-0.21,0.0,0.0,0.0,3.79,88.45
+2020-01-04 14:00:00,-0.39,14.0,0.0,14.0,4.21,88.45
+2020-01-04 15:00:00,-0.6,0.0,-0.0,0.0,4.28,88.45
+2020-01-04 16:00:00,-0.69,0.0,-0.0,0.0,4.21,91.95
+2020-01-04 17:00:00,-0.74,0.0,-0.0,0.0,4.14,88.4
+2020-01-04 18:00:00,-0.82,0.0,-0.0,0.0,4.14,88.4
+2020-01-04 19:00:00,-0.88,0.0,-0.0,0.0,4.07,88.4
+2020-01-04 20:00:00,-0.97,0.0,-0.0,0.0,4.14,88.4
+2020-01-04 21:00:00,-1.06,0.0,-0.0,0.0,4.21,88.4
+2020-01-04 22:00:00,-1.09,0.0,-0.0,0.0,4.21,88.4
+2020-01-04 23:00:00,-1.16,0.0,-0.0,0.0,4.07,88.4
+2020-01-05 00:00:00,-1.18,0.0,-0.0,0.0,4.0,91.9
+2020-01-05 01:00:00,-1.21,0.0,-0.0,0.0,3.72,91.9
+2020-01-05 02:00:00,-1.22,0.0,-0.0,0.0,3.45,95.6
+2020-01-05 03:00:00,-1.27,0.0,-0.0,0.0,3.1,95.6
+2020-01-05 04:00:00,-1.31,0.0,-0.0,0.0,2.69,95.6
+2020-01-05 05:00:00,-1.69,0.0,-0.0,0.0,2.14,99.4
+2020-01-05 06:00:00,-1.98,0.0,-0.0,0.0,2.28,95.55
+2020-01-05 07:00:00,-1.75,0.0,-0.0,0.0,2.83,99.4
+2020-01-05 08:00:00,-2.11,29.0,0.0,29.0,2.34,95.55
+2020-01-05 09:00:00,-2.65,0.0,0.0,0.0,2.41,95.55
+2020-01-05 10:00:00,-3.19,204.0,362.77,109.0,2.62,95.55
+2020-01-05 11:00:00,-3.77,0.0,0.0,0.0,2.9,91.8
+2020-01-05 12:00:00,-4.41,44.0,0.0,44.0,3.17,91.75
+2020-01-05 13:00:00,-5.4,0.0,0.0,0.0,3.93,88.05
+2020-01-05 14:00:00,-6.14,7.0,0.0,7.0,3.66,84.5
+2020-01-05 15:00:00,-6.85,0.0,-0.0,0.0,3.72,87.95
+2020-01-05 16:00:00,-7.51,0.0,-0.0,0.0,3.52,84.35
+2020-01-05 17:00:00,-8.26,0.0,-0.0,0.0,3.45,84.2
+2020-01-05 18:00:00,-8.8,0.0,-0.0,0.0,3.24,84.15
+2020-01-05 19:00:00,-8.96,0.0,-0.0,0.0,3.24,84.15
+2020-01-05 20:00:00,-9.73,0.0,-0.0,0.0,2.9,84.1
+2020-01-05 21:00:00,-10.3,0.0,-0.0,0.0,2.55,87.65
+2020-01-05 22:00:00,-11.22,0.0,-0.0,0.0,2.14,83.95
+2020-01-05 23:00:00,-12.51,0.0,-0.0,0.0,2.0,87.45
+2020-01-06 00:00:00,-14.15,0.0,-0.0,0.0,1.93,87.35
+2020-01-06 01:00:00,-15.69,0.0,-0.0,0.0,1.72,87.2
+2020-01-06 02:00:00,-16.52,0.0,-0.0,0.0,1.79,91.05
+2020-01-06 03:00:00,-17.51,0.0,-0.0,0.0,1.93,91.0
+2020-01-06 04:00:00,-19.15,0.0,-0.0,0.0,2.0,90.9
+2020-01-06 05:00:00,-19.41,0.0,-0.0,0.0,2.07,95.05
+2020-01-06 06:00:00,-19.32,0.0,-0.0,0.0,2.0,90.9
+2020-01-06 07:00:00,-18.5,0.0,-0.0,0.0,1.93,90.9
+2020-01-06 08:00:00,-19.67,65.0,149.7,48.0,2.07,90.85
+2020-01-06 09:00:00,-17.93,0.0,0.0,0.0,1.59,90.95
+2020-01-06 10:00:00,-14.27,146.0,79.69,125.0,0.83,80.1
+2020-01-06 11:00:00,-12.33,0.0,0.0,0.0,0.34,73.55
+2020-01-06 12:00:00,-11.19,160.0,117.82,129.0,0.14,67.7
+2020-01-06 13:00:00,-10.71,0.0,0.0,0.0,0.07,67.8
+2020-01-06 14:00:00,-10.87,60.0,124.51,46.0,0.07,73.8
+2020-01-06 15:00:00,-11.45,0.0,-0.0,0.0,0.07,77.0
+2020-01-06 16:00:00,-12.39,0.0,-0.0,0.0,0.76,83.75
+2020-01-06 17:00:00,-15.7,0.0,-0.0,0.0,1.79,87.2
+2020-01-06 18:00:00,-19.2,0.0,-0.0,0.0,2.34,90.9
+2020-01-06 19:00:00,-20.44,0.0,-0.0,0.0,2.21,90.8
+2020-01-06 20:00:00,-22.11,0.0,-0.0,0.0,2.41,90.65
+2020-01-06 21:00:00,-23.56,0.0,-0.0,0.0,2.41,90.55
+2020-01-06 22:00:00,-24.36,0.0,-0.0,0.0,2.28,78.7
+2020-01-06 23:00:00,-24.75,0.0,-0.0,0.0,2.28,78.6
+2020-01-07 00:00:00,-23.83,0.0,-0.0,0.0,2.14,82.45
+2020-01-07 01:00:00,-23.38,0.0,-0.0,0.0,2.21,82.55
+2020-01-07 02:00:00,-22.61,0.0,-0.0,0.0,2.21,82.6
+2020-01-07 03:00:00,-21.49,0.0,-0.0,0.0,2.21,82.7
+2020-01-07 04:00:00,-20.21,0.0,-0.0,0.0,2.28,79.2
+2020-01-07 05:00:00,-19.24,0.0,-0.0,0.0,2.48,79.35
+2020-01-07 06:00:00,-18.14,0.0,-0.0,0.0,2.55,83.2
+2020-01-07 07:00:00,-18.09,0.0,-0.0,0.0,2.62,83.2
+2020-01-07 08:00:00,-17.29,65.0,156.9,47.0,2.62,83.3
+2020-01-07 09:00:00,-15.06,0.0,0.0,0.0,2.69,79.95
+2020-01-07 10:00:00,-11.69,84.0,0.0,84.0,2.97,73.75
+2020-01-07 11:00:00,-8.31,0.0,0.0,0.0,3.45,65.4
+2020-01-07 12:00:00,-6.38,86.0,3.77,85.0,3.86,60.5
+2020-01-07 13:00:00,-5.7,0.0,0.0,0.0,4.28,66.05
+2020-01-07 14:00:00,-5.39,27.0,0.0,27.0,4.0,77.9
+2020-01-07 15:00:00,-5.18,0.0,-0.0,0.0,3.72,78.0
+2020-01-07 16:00:00,-5.12,0.0,-0.0,0.0,3.52,81.25
+2020-01-07 17:00:00,-4.97,0.0,-0.0,0.0,3.45,84.6
+2020-01-07 18:00:00,-4.66,0.0,-0.0,0.0,3.38,84.65
+2020-01-07 19:00:00,-5.16,0.0,-0.0,0.0,3.24,88.1
+2020-01-07 20:00:00,-5.06,0.0,-0.0,0.0,3.1,91.75
+2020-01-07 21:00:00,-5.09,0.0,-0.0,0.0,2.83,91.75
+2020-01-07 22:00:00,-5.22,0.0,-0.0,0.0,2.62,95.45
+2020-01-07 23:00:00,-5.42,0.0,-0.0,0.0,2.41,95.45
+2020-01-08 00:00:00,-5.59,0.0,-0.0,0.0,2.21,91.7
+2020-01-08 01:00:00,-5.76,0.0,-0.0,0.0,2.14,95.45
+2020-01-08 02:00:00,-6.02,0.0,-0.0,0.0,2.0,91.7
+2020-01-08 03:00:00,-6.33,0.0,-0.0,0.0,1.93,95.45
+2020-01-08 04:00:00,-6.42,0.0,-0.0,0.0,1.86,95.45
+2020-01-08 05:00:00,-6.57,0.0,-0.0,0.0,1.79,91.65
+2020-01-08 06:00:00,-6.97,0.0,-0.0,0.0,1.72,91.6
+2020-01-08 07:00:00,-7.09,0.0,-0.0,0.0,1.38,91.6
+2020-01-08 08:00:00,-7.21,52.0,51.72,46.0,1.24,91.6
+2020-01-08 09:00:00,-6.7,0.0,0.0,0.0,1.45,91.65
+2020-01-08 10:00:00,-6.03,85.0,0.0,85.0,1.66,88.0
+2020-01-08 11:00:00,-5.32,0.0,0.0,0.0,1.72,84.55
+2020-01-08 12:00:00,-4.92,166.0,141.86,128.0,1.59,78.0
+2020-01-08 13:00:00,-4.86,0.0,0.0,0.0,1.45,78.0
+2020-01-08 14:00:00,-5.39,61.0,110.28,48.0,1.24,77.9
+2020-01-08 15:00:00,-6.94,0.0,-0.0,0.0,1.45,77.7
+2020-01-08 16:00:00,-9.78,0.0,-0.0,0.0,2.21,80.55
+2020-01-08 17:00:00,-12.48,0.0,-0.0,0.0,2.28,87.45
+2020-01-08 18:00:00,-14.29,0.0,-0.0,0.0,2.34,83.65
+2020-01-08 19:00:00,-14.62,0.0,-0.0,0.0,2.48,91.2
+2020-01-08 20:00:00,-14.87,0.0,-0.0,0.0,2.62,91.15
+2020-01-08 21:00:00,-14.47,0.0,-0.0,0.0,2.69,91.2
+2020-01-08 22:00:00,-14.08,0.0,-0.0,0.0,2.69,87.35
+2020-01-08 23:00:00,-13.85,0.0,-0.0,0.0,2.62,87.35
+2020-01-09 00:00:00,-14.1,0.0,-0.0,0.0,2.62,87.35
+2020-01-09 01:00:00,-14.76,0.0,-0.0,0.0,2.48,83.6
+2020-01-09 02:00:00,-15.29,0.0,-0.0,0.0,2.48,83.55
+2020-01-09 03:00:00,-15.74,0.0,-0.0,0.0,2.48,87.2
+2020-01-09 04:00:00,-16.1,0.0,-0.0,0.0,2.55,87.15
+2020-01-09 05:00:00,-16.32,0.0,-0.0,0.0,2.55,91.05
+2020-01-09 06:00:00,-16.47,0.0,-0.0,0.0,2.48,87.1
+2020-01-09 07:00:00,-14.95,0.0,-0.0,0.0,2.55,91.15
+2020-01-09 08:00:00,-13.46,70.0,195.88,47.0,2.55,87.4
+2020-01-09 09:00:00,-11.76,0.0,0.0,0.0,2.41,83.9
+2020-01-09 10:00:00,-9.92,177.0,185.73,127.0,2.28,84.05
+2020-01-09 11:00:00,-7.91,0.0,0.0,0.0,2.07,77.55
+2020-01-09 12:00:00,-6.47,161.0,125.73,127.0,1.66,74.6
+2020-01-09 13:00:00,-5.92,0.0,0.0,0.0,1.45,74.7
+2020-01-09 14:00:00,-6.29,53.0,57.97,46.0,1.52,77.75
+2020-01-09 15:00:00,-7.72,0.0,0.0,0.0,2.07,77.6
+2020-01-09 16:00:00,-9.61,0.0,-0.0,0.0,2.07,80.65
+2020-01-09 17:00:00,-11.24,0.0,-0.0,0.0,2.0,83.95
+2020-01-09 18:00:00,-12.23,0.0,-0.0,0.0,1.93,87.5
+2020-01-09 19:00:00,-11.78,0.0,-0.0,0.0,2.07,87.5
+2020-01-09 20:00:00,-11.89,0.0,-0.0,0.0,2.14,87.5
+2020-01-09 21:00:00,-11.55,0.0,-0.0,0.0,2.14,83.9
+2020-01-09 22:00:00,-10.83,0.0,-0.0,0.0,2.14,83.95
+2020-01-09 23:00:00,-10.55,0.0,-0.0,0.0,2.14,80.5
+2020-01-10 00:00:00,-9.85,0.0,-0.0,0.0,2.0,80.55
+2020-01-10 01:00:00,-10.0,0.0,-0.0,0.0,2.14,80.55
+2020-01-10 02:00:00,-9.97,0.0,-0.0,0.0,2.07,80.55
+2020-01-10 03:00:00,-9.62,0.0,-0.0,0.0,1.93,80.65
+2020-01-10 04:00:00,-9.28,0.0,-0.0,0.0,1.79,80.65
+2020-01-10 05:00:00,-9.03,0.0,-0.0,0.0,1.86,80.7
+2020-01-10 06:00:00,-8.93,0.0,-0.0,0.0,2.07,80.7
+2020-01-10 07:00:00,-7.89,0.0,-0.0,0.0,2.34,80.85
+2020-01-10 08:00:00,-7.44,48.0,42.03,43.0,2.34,84.35
+2020-01-10 09:00:00,-6.25,0.0,0.0,0.0,2.21,84.45
+2020-01-10 10:00:00,-5.01,126.0,40.54,115.0,2.34,81.25
+2020-01-10 11:00:00,-3.97,0.0,0.0,0.0,2.48,78.15
+2020-01-10 12:00:00,-3.23,184.0,212.38,126.0,2.55,75.1
+2020-01-10 13:00:00,-2.85,0.0,0.0,0.0,2.48,75.2
+2020-01-10 14:00:00,-3.19,65.0,129.33,49.0,2.28,78.2
+2020-01-10 15:00:00,-4.45,0.0,0.0,0.0,2.41,78.05
+2020-01-10 16:00:00,-5.86,0.0,-0.0,0.0,2.69,81.1
+2020-01-10 17:00:00,-6.76,0.0,-0.0,0.0,2.97,81.0
+2020-01-10 18:00:00,-7.19,0.0,-0.0,0.0,3.1,77.7
+2020-01-10 19:00:00,-6.95,0.0,-0.0,0.0,3.24,81.0
+2020-01-10 20:00:00,-6.84,0.0,-0.0,0.0,3.31,81.0
+2020-01-10 21:00:00,-6.95,0.0,-0.0,0.0,3.38,81.0
+2020-01-10 22:00:00,-7.12,0.0,-0.0,0.0,3.31,77.7
+2020-01-10 23:00:00,-7.38,0.0,-0.0,0.0,3.17,80.9
+2020-01-11 00:00:00,-7.69,0.0,-0.0,0.0,3.17,77.6
+2020-01-11 01:00:00,-7.78,0.0,-0.0,0.0,3.17,80.85
+2020-01-11 02:00:00,-8.13,0.0,-0.0,0.0,3.03,80.85
+2020-01-11 03:00:00,-8.57,0.0,-0.0,0.0,2.76,80.8
+2020-01-11 04:00:00,-9.22,0.0,-0.0,0.0,2.69,80.7
+2020-01-11 05:00:00,-9.72,0.0,-0.0,0.0,2.83,80.65
+2020-01-11 06:00:00,-9.88,0.0,-0.0,0.0,3.17,84.05
+2020-01-11 07:00:00,-8.84,0.0,-0.0,0.0,3.31,84.15
+2020-01-11 08:00:00,-8.42,74.0,215.58,48.0,3.1,84.2
+2020-01-11 09:00:00,-7.37,0.0,0.0,0.0,2.76,80.9
+2020-01-11 10:00:00,-5.95,188.0,219.29,128.0,2.69,74.7
+2020-01-11 11:00:00,-4.47,0.0,0.0,0.0,2.55,71.95
+2020-01-11 12:00:00,-3.39,180.0,177.62,131.0,2.41,72.1
+2020-01-11 13:00:00,-2.82,0.0,0.0,0.0,2.34,72.25
+2020-01-11 14:00:00,-3.12,69.0,141.99,51.0,2.55,72.25
+2020-01-11 15:00:00,-4.05,0.0,0.0,0.0,2.76,75.05
+2020-01-11 16:00:00,-5.71,0.0,-0.0,0.0,2.97,77.9
+2020-01-11 17:00:00,-6.78,0.0,-0.0,0.0,3.1,81.0
+2020-01-11 18:00:00,-7.6,0.0,-0.0,0.0,3.17,80.9
+2020-01-11 19:00:00,-7.78,0.0,-0.0,0.0,3.38,80.85
+2020-01-11 20:00:00,-7.81,0.0,-0.0,0.0,3.38,80.85
+2020-01-11 21:00:00,-7.81,0.0,-0.0,0.0,3.38,80.85
+2020-01-11 22:00:00,-7.88,0.0,-0.0,0.0,3.38,80.85
+2020-01-11 23:00:00,-7.84,0.0,-0.0,0.0,3.52,80.85
+2020-01-12 00:00:00,-7.71,0.0,-0.0,0.0,3.45,77.6
+2020-01-12 01:00:00,-7.87,0.0,-0.0,0.0,3.38,77.55
+2020-01-12 02:00:00,-8.24,0.0,-0.0,0.0,3.38,80.8
+2020-01-12 03:00:00,-8.61,0.0,-0.0,0.0,3.45,77.45
+2020-01-12 04:00:00,-8.91,0.0,-0.0,0.0,3.59,80.7
+2020-01-12 05:00:00,-9.06,0.0,-0.0,0.0,3.72,77.35
+2020-01-12 06:00:00,-8.99,0.0,-0.0,0.0,3.93,77.35
+2020-01-12 07:00:00,-8.72,0.0,0.0,0.0,4.14,74.25
+2020-01-12 08:00:00,-8.65,78.0,236.98,49.0,4.14,74.25
+2020-01-12 09:00:00,-7.56,126.0,120.19,100.0,4.28,71.4
+2020-01-12 10:00:00,-6.23,209.0,307.99,124.0,4.0,71.55
+2020-01-12 11:00:00,-4.61,222.0,282.57,138.0,3.93,63.55
+2020-01-12 12:00:00,-3.32,201.0,254.71,130.0,4.14,63.8
+2020-01-12 13:00:00,-2.63,156.0,261.65,98.0,4.0,63.9
+2020-01-12 14:00:00,-2.9,72.0,138.54,54.0,4.0,61.35
+2020-01-12 15:00:00,-4.02,0.0,0.0,0.0,3.93,63.7
+2020-01-12 16:00:00,-5.23,0.0,-0.0,0.0,4.14,68.85
+2020-01-12 17:00:00,-5.83,0.0,-0.0,0.0,4.34,71.65
+2020-01-12 18:00:00,-5.89,0.0,-0.0,0.0,4.48,71.65
+2020-01-12 19:00:00,-7.14,0.0,-0.0,0.0,4.83,71.5
+2020-01-12 20:00:00,-7.11,0.0,-0.0,0.0,4.83,71.5
+2020-01-12 21:00:00,-7.13,0.0,-0.0,0.0,4.83,74.55
+2020-01-12 22:00:00,-7.23,0.0,-0.0,0.0,4.83,74.55
+2020-01-12 23:00:00,-7.27,0.0,-0.0,0.0,4.69,74.45
+2020-01-13 00:00:00,-7.35,0.0,-0.0,0.0,4.48,74.45
+2020-01-13 01:00:00,-7.25,0.0,-0.0,0.0,4.34,74.45
+2020-01-13 02:00:00,-7.19,0.0,-0.0,0.0,4.28,71.5
+2020-01-13 03:00:00,-7.06,0.0,-0.0,0.0,4.41,71.5
+2020-01-13 04:00:00,-6.91,0.0,-0.0,0.0,4.34,71.5
+2020-01-13 05:00:00,-6.91,0.0,-0.0,0.0,4.34,71.5
+2020-01-13 06:00:00,-6.81,0.0,-0.0,0.0,4.28,71.5
+2020-01-13 07:00:00,-6.52,0.0,0.0,0.0,4.41,71.55
+2020-01-13 08:00:00,-6.13,72.0,177.04,50.0,4.41,71.65
+2020-01-13 09:00:00,-4.8,130.0,137.28,100.0,4.21,68.95
+2020-01-13 10:00:00,-3.01,229.0,427.32,110.0,4.21,63.9
+2020-01-13 11:00:00,-1.4,243.0,393.28,125.0,3.72,66.8
+2020-01-13 12:00:00,-0.25,222.0,365.58,119.0,3.86,64.35
+2020-01-13 13:00:00,0.12,181.0,435.89,83.0,3.59,64.45
+2020-01-13 14:00:00,-0.44,69.0,105.12,55.0,3.45,67.0
+2020-01-13 15:00:00,-1.76,0.0,0.0,0.0,3.38,72.3
+2020-01-13 16:00:00,-3.26,0.0,-0.0,0.0,3.38,72.1
+2020-01-13 17:00:00,-4.31,0.0,-0.0,0.0,3.38,74.95
+2020-01-13 18:00:00,-5.04,0.0,-0.0,0.0,3.66,74.9
+2020-01-13 19:00:00,-6.43,0.0,-0.0,0.0,3.86,77.75
+2020-01-13 20:00:00,-6.54,0.0,-0.0,0.0,4.14,77.75
+2020-01-13 21:00:00,-6.6,0.0,-0.0,0.0,4.07,77.75
+2020-01-13 22:00:00,-6.89,0.0,-0.0,0.0,3.59,81.0
+2020-01-13 23:00:00,-7.36,0.0,-0.0,0.0,3.38,80.9
+2020-01-14 00:00:00,-7.93,0.0,-0.0,0.0,3.38,80.85
+2020-01-14 01:00:00,-8.43,0.0,-0.0,0.0,3.38,80.8
+2020-01-14 02:00:00,-8.78,0.0,-0.0,0.0,3.38,84.15
+2020-01-14 03:00:00,-9.06,0.0,-0.0,0.0,3.31,80.7
+2020-01-14 04:00:00,-9.3,0.0,-0.0,0.0,3.17,84.1
+2020-01-14 05:00:00,-9.64,0.0,-0.0,0.0,3.03,80.65
+2020-01-14 06:00:00,-10.03,0.0,-0.0,0.0,2.9,80.55
+2020-01-14 07:00:00,-8.75,0.0,0.0,0.0,2.9,84.15
+2020-01-14 08:00:00,-8.49,65.0,102.95,52.0,2.69,80.8
+2020-01-14 09:00:00,-7.14,99.0,36.23,91.0,2.34,77.7
+2020-01-14 10:00:00,-5.38,137.0,46.25,124.0,2.21,74.8
+2020-01-14 11:00:00,-3.6,105.0,3.3,104.0,1.93,72.1
+2020-01-14 12:00:00,-2.09,105.0,7.02,103.0,1.72,72.3
+2020-01-14 13:00:00,-1.34,98.0,30.69,91.0,1.59,75.35
+2020-01-14 14:00:00,-1.21,55.0,36.62,50.0,1.45,78.45
+2020-01-14 15:00:00,-2.03,0.0,0.0,0.0,1.72,81.55
+2020-01-14 16:00:00,-2.98,0.0,-0.0,0.0,1.86,81.5
+2020-01-14 17:00:00,-3.57,0.0,-0.0,0.0,1.93,81.45
+2020-01-14 18:00:00,-3.8,0.0,-0.0,0.0,2.0,81.4
+2020-01-14 19:00:00,-3.83,0.0,-0.0,0.0,2.07,84.7
+2020-01-14 20:00:00,-3.81,0.0,-0.0,0.0,2.14,88.2
+2020-01-14 21:00:00,-3.32,0.0,-0.0,0.0,2.14,88.25
+2020-01-14 22:00:00,-2.55,0.0,-0.0,0.0,2.07,91.85
+2020-01-14 23:00:00,-1.48,0.0,-0.0,0.0,2.07,91.9
+2020-01-15 00:00:00,-0.63,0.0,-0.0,0.0,2.14,91.95
+2020-01-15 01:00:00,-0.19,0.0,-0.0,0.0,2.14,95.6
+2020-01-15 02:00:00,0.06,0.0,-0.0,0.0,2.21,95.6
+2020-01-15 03:00:00,0.21,0.0,-0.0,0.0,2.28,95.6
+2020-01-15 04:00:00,0.3,0.0,-0.0,0.0,2.28,99.4
+2020-01-15 05:00:00,0.37,0.0,-0.0,0.0,2.14,95.65
+2020-01-15 06:00:00,0.41,0.0,-0.0,0.0,2.07,95.65
+2020-01-15 07:00:00,0.36,0.0,0.0,0.0,2.07,95.65
+2020-01-15 08:00:00,0.49,49.0,31.15,45.0,1.93,95.65
+2020-01-15 09:00:00,0.74,63.0,0.0,63.0,1.72,99.4
+2020-01-15 10:00:00,1.02,53.0,0.0,53.0,1.93,95.65
+2020-01-15 11:00:00,1.17,67.0,0.0,67.0,1.79,99.35
+2020-01-15 12:00:00,1.28,65.0,0.0,65.0,1.86,99.35
+2020-01-15 13:00:00,1.33,73.0,4.32,72.0,1.86,99.35
+2020-01-15 14:00:00,1.14,35.0,0.0,35.0,1.72,99.35
+2020-01-15 15:00:00,0.87,0.0,0.0,0.0,1.52,99.35
+2020-01-15 16:00:00,0.7,0.0,-0.0,0.0,1.38,99.4
+2020-01-15 17:00:00,0.51,0.0,-0.0,0.0,1.24,99.4
+2020-01-15 18:00:00,0.33,0.0,-0.0,0.0,1.24,100.0
+2020-01-15 19:00:00,0.23,0.0,-0.0,0.0,1.31,99.4
+2020-01-15 20:00:00,-0.15,0.0,-0.0,0.0,1.24,95.6
+2020-01-15 21:00:00,-0.34,0.0,-0.0,0.0,1.1,99.4
+2020-01-15 22:00:00,-0.65,0.0,-0.0,0.0,1.03,95.6
+2020-01-15 23:00:00,-0.77,0.0,-0.0,0.0,0.9,99.4
+2020-01-16 00:00:00,-0.93,0.0,-0.0,0.0,0.9,99.4
+2020-01-16 01:00:00,-0.69,0.0,-0.0,0.0,0.69,99.4
+2020-01-16 02:00:00,-0.19,0.0,-0.0,0.0,0.48,99.4
+2020-01-16 03:00:00,-0.28,0.0,-0.0,0.0,0.48,95.6
+2020-01-16 04:00:00,-0.98,0.0,-0.0,0.0,0.9,95.6
+2020-01-16 05:00:00,-1.37,0.0,-0.0,0.0,1.1,99.4
+2020-01-16 06:00:00,-1.77,0.0,-0.0,0.0,1.24,99.4
+2020-01-16 07:00:00,-1.22,0.0,0.0,0.0,0.97,99.4
+2020-01-16 08:00:00,-1.46,66.0,99.5,53.0,0.97,99.4
+2020-01-16 09:00:00,-1.22,92.0,22.14,87.0,1.45,99.4
+2020-01-16 10:00:00,-0.53,142.0,52.33,127.0,1.66,95.6
+2020-01-16 11:00:00,0.0,229.0,288.03,140.0,1.79,92.0
+2020-01-16 12:00:00,0.14,222.0,329.51,126.0,1.79,92.0
+2020-01-16 13:00:00,0.31,166.0,272.48,102.0,2.0,88.45
+2020-01-16 14:00:00,0.28,76.0,118.49,59.0,2.14,88.45
+2020-01-16 15:00:00,-0.24,0.0,0.0,0.0,1.86,91.95
+2020-01-16 16:00:00,-0.59,0.0,-0.0,0.0,2.14,88.45
+2020-01-16 17:00:00,-0.85,0.0,-0.0,0.0,2.41,91.95
+2020-01-16 18:00:00,-1.07,0.0,-0.0,0.0,2.69,88.4
+2020-01-16 19:00:00,-1.06,0.0,-0.0,0.0,2.62,91.95
+2020-01-16 20:00:00,-1.11,0.0,-0.0,0.0,2.83,91.95
+2020-01-16 21:00:00,-1.54,0.0,-0.0,0.0,3.03,91.9
+2020-01-16 22:00:00,-1.36,0.0,-0.0,0.0,3.17,91.9
+2020-01-16 23:00:00,-1.71,0.0,-0.0,0.0,3.03,95.55
+2020-01-17 00:00:00,-1.88,0.0,-0.0,0.0,2.97,91.85
+2020-01-17 01:00:00,-2.05,0.0,-0.0,0.0,2.9,91.85
+2020-01-17 02:00:00,-2.15,0.0,-0.0,0.0,2.83,91.85
+2020-01-17 03:00:00,-2.22,0.0,-0.0,0.0,2.83,95.55
+2020-01-17 04:00:00,-2.27,0.0,-0.0,0.0,2.83,95.55
+2020-01-17 05:00:00,-2.23,0.0,-0.0,0.0,2.83,95.55
+2020-01-17 06:00:00,-2.24,0.0,-0.0,0.0,2.9,95.55
+2020-01-17 07:00:00,-1.73,0.0,0.0,0.0,2.83,91.85
+2020-01-17 08:00:00,-1.85,28.0,0.0,28.0,2.62,91.85
+2020-01-17 09:00:00,-1.18,108.0,52.52,96.0,2.41,88.35
+2020-01-17 10:00:00,-0.12,182.0,162.29,135.0,2.21,81.8
+2020-01-17 11:00:00,0.96,236.0,323.51,135.0,2.55,78.8
+2020-01-17 12:00:00,1.66,65.0,0.0,65.0,2.48,82.0
+2020-01-17 13:00:00,1.92,28.0,0.0,28.0,2.21,82.05
+2020-01-17 14:00:00,1.9,68.0,67.99,58.0,2.07,82.05
+2020-01-17 15:00:00,1.63,0.0,0.0,0.0,2.14,85.25
+2020-01-17 16:00:00,1.53,0.0,-0.0,0.0,2.21,85.25
+2020-01-17 17:00:00,1.54,0.0,-0.0,0.0,2.34,85.25
+2020-01-17 18:00:00,1.57,0.0,-0.0,0.0,2.41,85.25
+2020-01-17 19:00:00,1.86,0.0,-0.0,0.0,2.69,85.3
+2020-01-17 20:00:00,1.9,0.0,-0.0,0.0,2.69,85.3
+2020-01-17 21:00:00,2.04,0.0,-0.0,0.0,2.55,88.65
+2020-01-17 22:00:00,2.12,0.0,-0.0,0.0,2.55,88.65
+2020-01-17 23:00:00,1.93,0.0,-0.0,0.0,2.41,88.65
+2020-01-18 00:00:00,1.72,0.0,-0.0,0.0,2.34,88.6
+2020-01-18 01:00:00,1.96,0.0,-0.0,0.0,2.62,88.65
+2020-01-18 02:00:00,2.23,0.0,-0.0,0.0,2.69,88.65
+2020-01-18 03:00:00,2.15,0.0,-0.0,0.0,2.41,88.65
+2020-01-18 04:00:00,1.77,0.0,-0.0,0.0,2.07,92.05
+2020-01-18 05:00:00,1.34,0.0,-0.0,0.0,2.21,95.65
+2020-01-18 06:00:00,1.01,0.0,-0.0,0.0,2.41,92.05
+2020-01-18 07:00:00,0.93,0.0,0.0,0.0,2.48,92.05
+2020-01-18 08:00:00,1.22,59.0,51.66,52.0,2.9,92.05
+2020-01-18 09:00:00,1.83,97.0,25.94,91.0,3.31,92.05
+2020-01-18 10:00:00,2.73,257.0,574.05,89.0,3.52,88.65
+2020-01-18 11:00:00,3.31,263.0,462.75,117.0,3.79,88.7
+2020-01-18 12:00:00,3.74,242.0,432.53,113.0,4.07,85.45
+2020-01-18 13:00:00,3.83,209.0,574.25,70.0,4.07,85.45
+2020-01-18 14:00:00,3.72,56.0,19.9,53.0,4.0,85.45
+2020-01-18 15:00:00,3.26,6.0,0.0,6.0,3.93,88.7
+2020-01-18 16:00:00,3.01,0.0,-0.0,0.0,3.93,85.4
+2020-01-18 17:00:00,3.19,0.0,-0.0,0.0,4.14,85.4
+2020-01-18 18:00:00,3.58,0.0,-0.0,0.0,4.76,82.25
+2020-01-18 19:00:00,2.97,0.0,-0.0,0.0,4.21,85.4
+2020-01-18 20:00:00,3.0,0.0,-0.0,0.0,4.34,85.4
+2020-01-18 21:00:00,2.97,0.0,-0.0,0.0,4.69,85.4
+2020-01-18 22:00:00,2.95,0.0,-0.0,0.0,5.24,85.4
+2020-01-18 23:00:00,2.84,0.0,-0.0,0.0,5.38,88.65
+2020-01-19 00:00:00,2.54,0.0,-0.0,0.0,5.38,88.65
+2020-01-19 01:00:00,2.26,0.0,-0.0,0.0,5.31,88.65
+2020-01-19 02:00:00,2.01,0.0,-0.0,0.0,4.97,85.3
+2020-01-19 03:00:00,1.67,0.0,-0.0,0.0,4.55,85.25
+2020-01-19 04:00:00,1.09,0.0,-0.0,0.0,4.14,85.2
+2020-01-19 05:00:00,0.72,0.0,-0.0,0.0,3.59,88.5
+2020-01-19 06:00:00,0.34,0.0,-0.0,0.0,2.97,85.15
+2020-01-19 07:00:00,0.36,0.0,0.0,0.0,2.34,88.5
+2020-01-19 08:00:00,0.16,102.0,405.52,46.0,2.21,88.45
+2020-01-19 09:00:00,1.05,167.0,281.87,101.0,2.55,88.55
+2020-01-19 10:00:00,2.27,281.0,720.02,68.0,3.31,85.3
+2020-01-19 11:00:00,2.67,295.0,649.08,88.0,4.34,79.0
+2020-01-19 12:00:00,2.86,192.0,162.34,143.0,4.62,79.0
+2020-01-19 13:00:00,2.97,110.0,36.62,101.0,5.17,76.1
+2020-01-19 14:00:00,2.7,41.0,0.0,41.0,5.1,79.0
+2020-01-19 15:00:00,2.13,1.0,0.0,1.0,5.31,85.3
+2020-01-19 16:00:00,2.19,0.0,-0.0,0.0,5.72,85.3
+2020-01-19 17:00:00,2.54,0.0,-0.0,0.0,6.14,82.15
+2020-01-19 18:00:00,2.7,0.0,-0.0,0.0,5.86,79.0
+2020-01-19 19:00:00,2.93,0.0,-0.0,0.0,4.9,76.1
+2020-01-19 20:00:00,3.08,0.0,-0.0,0.0,4.55,76.1
+2020-01-19 21:00:00,2.65,0.0,-0.0,0.0,4.41,79.0
+2020-01-19 22:00:00,2.75,0.0,-0.0,0.0,4.14,79.0
+2020-01-19 23:00:00,3.05,0.0,-0.0,0.0,3.86,79.1
+2020-01-20 00:00:00,2.83,0.0,-0.0,0.0,3.72,82.15
+2020-01-20 01:00:00,2.65,0.0,-0.0,0.0,3.66,85.35
+2020-01-20 02:00:00,2.61,0.0,-0.0,0.0,3.66,85.35
+2020-01-20 03:00:00,2.79,0.0,-0.0,0.0,3.59,85.35
+2020-01-20 04:00:00,2.81,0.0,-0.0,0.0,3.31,85.35
+2020-01-20 05:00:00,2.77,0.0,-0.0,0.0,2.9,85.35
+2020-01-20 06:00:00,2.79,0.0,-0.0,0.0,2.55,88.65
+2020-01-20 07:00:00,2.97,0.0,0.0,0.0,2.34,88.7
+2020-01-20 08:00:00,2.84,51.0,21.31,48.0,2.07,95.7
+2020-01-20 09:00:00,2.97,73.0,0.0,73.0,1.86,92.15
+2020-01-20 10:00:00,3.55,25.0,0.0,25.0,1.66,92.15
+2020-01-20 11:00:00,4.79,210.0,179.89,152.0,1.52,92.25
+2020-01-20 12:00:00,4.81,165.0,81.82,140.0,1.45,92.25
+2020-01-20 13:00:00,4.78,123.0,60.1,108.0,1.31,92.25
+2020-01-20 14:00:00,4.95,62.0,25.26,58.0,1.31,88.85
+2020-01-20 15:00:00,3.84,10.0,0.0,10.0,1.38,95.7
+2020-01-20 16:00:00,1.55,0.0,-0.0,0.0,1.86,95.65
+2020-01-20 17:00:00,0.03,0.0,-0.0,0.0,1.93,95.6
+2020-01-20 18:00:00,-0.2,0.0,-0.0,0.0,1.52,99.4
+2020-01-20 19:00:00,-1.86,0.0,-0.0,0.0,1.72,99.4
+2020-01-20 20:00:00,-1.73,0.0,-0.0,0.0,1.72,99.4
+2020-01-20 21:00:00,-1.45,0.0,-0.0,0.0,1.59,99.4
+2020-01-20 22:00:00,-1.29,0.0,-0.0,0.0,1.52,99.4
+2020-01-20 23:00:00,-1.29,0.0,-0.0,0.0,1.38,99.4
+2020-01-21 00:00:00,-1.4,0.0,-0.0,0.0,1.24,99.4
+2020-01-21 01:00:00,-1.53,0.0,-0.0,0.0,1.17,95.6
+2020-01-21 02:00:00,-1.61,0.0,-0.0,0.0,1.1,95.6
+2020-01-21 03:00:00,-1.68,0.0,-0.0,0.0,1.03,99.4
+2020-01-21 04:00:00,-1.43,0.0,-0.0,0.0,0.83,99.4
+2020-01-21 05:00:00,-1.6,0.0,-0.0,0.0,0.83,95.6
+2020-01-21 06:00:00,-1.12,0.0,-0.0,0.0,0.62,95.6
+2020-01-21 07:00:00,0.08,0.0,0.0,0.0,0.55,95.6
+2020-01-21 08:00:00,0.36,72.0,97.48,58.0,0.55,95.65
+2020-01-21 09:00:00,0.43,63.0,0.0,63.0,0.97,99.4
+2020-01-21 10:00:00,1.21,132.0,26.45,124.0,1.17,99.35
+2020-01-21 11:00:00,1.36,102.0,0.0,102.0,1.31,95.65
+2020-01-21 12:00:00,1.66,81.0,0.0,81.0,1.38,99.4
+2020-01-21 13:00:00,1.54,77.0,0.0,77.0,1.45,99.4
+2020-01-21 14:00:00,1.4,40.0,0.0,40.0,1.38,99.4
+2020-01-21 15:00:00,1.14,9.0,0.0,9.0,1.38,99.35
+2020-01-21 16:00:00,0.98,0.0,-0.0,0.0,1.59,99.35
+2020-01-21 17:00:00,0.88,0.0,-0.0,0.0,1.66,99.35
+2020-01-21 18:00:00,0.82,0.0,-0.0,0.0,1.86,100.0
+2020-01-21 19:00:00,0.93,0.0,-0.0,0.0,1.79,95.65
+2020-01-21 20:00:00,0.81,0.0,-0.0,0.0,1.79,99.4
+2020-01-21 21:00:00,0.76,0.0,-0.0,0.0,1.86,99.4
+2020-01-21 22:00:00,0.66,0.0,-0.0,0.0,1.93,95.65
+2020-01-21 23:00:00,0.41,0.0,-0.0,0.0,2.07,95.65
+2020-01-22 00:00:00,0.33,0.0,-0.0,0.0,2.07,99.4
+2020-01-22 01:00:00,-0.07,0.0,-0.0,0.0,2.21,95.6
+2020-01-22 02:00:00,-0.09,0.0,-0.0,0.0,2.28,95.6
+2020-01-22 03:00:00,-0.23,0.0,-0.0,0.0,2.21,95.6
+2020-01-22 04:00:00,-0.26,0.0,-0.0,0.0,2.14,95.6
+2020-01-22 05:00:00,-0.07,0.0,-0.0,0.0,2.14,92.0
+2020-01-22 06:00:00,-0.34,0.0,-0.0,0.0,2.0,95.6
+2020-01-22 07:00:00,-0.89,0.0,0.0,0.0,1.59,95.6
+2020-01-22 08:00:00,-1.32,113.0,470.81,44.0,1.45,95.6
+2020-01-22 09:00:00,-0.54,170.0,254.64,108.0,1.31,91.95
+2020-01-22 10:00:00,1.46,303.0,794.21,60.0,1.86,85.25
+2020-01-22 11:00:00,2.75,329.0,806.7,63.0,2.0,79.0
+2020-01-22 12:00:00,3.42,303.0,747.15,69.0,2.28,76.15
+2020-01-22 13:00:00,2.83,242.0,722.49,56.0,2.55,82.15
+2020-01-22 14:00:00,2.37,123.0,384.85,59.0,2.48,82.15
+2020-01-22 15:00:00,1.29,22.0,239.32,11.0,2.76,88.55
+2020-01-22 16:00:00,0.17,0.0,-0.0,0.0,3.1,92.0
+2020-01-22 17:00:00,-0.15,0.0,-0.0,0.0,3.24,88.45
+2020-01-22 18:00:00,-0.28,0.0,-0.0,0.0,3.45,91.95
+2020-01-22 19:00:00,0.27,0.0,-0.0,0.0,3.45,88.45
+2020-01-22 20:00:00,0.37,0.0,-0.0,0.0,3.72,85.15
+2020-01-22 21:00:00,0.06,0.0,-0.0,0.0,3.86,88.45
+2020-01-22 22:00:00,-0.23,0.0,-0.0,0.0,4.0,88.45
+2020-01-22 23:00:00,-0.35,0.0,-0.0,0.0,4.0,88.45
+2020-01-23 00:00:00,-0.38,0.0,-0.0,0.0,4.0,88.45
+2020-01-23 01:00:00,-1.02,0.0,-0.0,0.0,4.07,88.4
+2020-01-23 02:00:00,-0.88,0.0,-0.0,0.0,4.07,91.95
+2020-01-23 03:00:00,-0.94,0.0,-0.0,0.0,4.0,91.95
+2020-01-23 04:00:00,-1.05,0.0,-0.0,0.0,4.0,91.95
+2020-01-23 05:00:00,-1.35,0.0,-0.0,0.0,4.21,91.9
+2020-01-23 06:00:00,-1.49,0.0,-0.0,0.0,4.41,91.9
+2020-01-23 07:00:00,-1.66,0.0,0.0,0.0,4.69,88.35
+2020-01-23 08:00:00,-1.4,126.0,601.62,36.0,4.69,91.9
+2020-01-23 09:00:00,-0.92,225.0,668.53,60.0,5.24,88.4
+2020-01-23 10:00:00,-0.24,174.0,93.68,145.0,5.66,88.45
+2020-01-23 11:00:00,0.52,179.0,71.96,155.0,5.72,85.15
+2020-01-23 12:00:00,1.15,162.0,59.91,143.0,5.93,85.2
+2020-01-23 13:00:00,1.7,55.0,0.0,55.0,5.86,85.25
+2020-01-23 14:00:00,1.95,52.0,5.87,51.0,6.07,82.05
+2020-01-23 15:00:00,2.07,14.0,20.01,13.0,5.79,82.05
+2020-01-23 16:00:00,1.97,0.0,-0.0,0.0,5.72,85.3
+2020-01-23 17:00:00,2.06,0.0,-0.0,0.0,5.93,88.65
+2020-01-23 18:00:00,2.3,0.0,-0.0,0.0,5.79,88.65
+2020-01-23 19:00:00,1.91,0.0,-0.0,0.0,5.24,85.3
+2020-01-23 20:00:00,2.08,0.0,-0.0,0.0,4.41,85.3
+2020-01-23 21:00:00,2.54,0.0,-0.0,0.0,3.79,85.35
+2020-01-23 22:00:00,3.39,0.0,-0.0,0.0,3.93,82.25
+2020-01-23 23:00:00,3.71,0.0,-0.0,0.0,4.48,82.25
+2020-01-24 00:00:00,3.46,0.0,-0.0,0.0,4.69,79.15
+2020-01-24 01:00:00,3.74,0.0,-0.0,0.0,4.76,82.25
+2020-01-24 02:00:00,3.44,0.0,-0.0,0.0,4.9,82.25
+2020-01-24 03:00:00,3.23,0.0,-0.0,0.0,4.97,85.4
+2020-01-24 04:00:00,3.08,0.0,-0.0,0.0,4.97,85.4
+2020-01-24 05:00:00,2.84,0.0,-0.0,0.0,4.9,85.35
+2020-01-24 06:00:00,2.53,0.0,-0.0,0.0,4.76,82.15
+2020-01-24 07:00:00,2.48,6.0,0.0,6.0,3.79,85.35
+2020-01-24 08:00:00,2.52,59.0,26.19,55.0,3.45,85.35
+2020-01-24 09:00:00,2.84,75.0,0.0,75.0,3.31,85.35
+2020-01-24 10:00:00,3.35,137.0,25.54,129.0,3.72,82.2
+2020-01-24 11:00:00,3.53,327.0,752.74,73.0,3.38,76.15
+2020-01-24 12:00:00,3.94,312.0,769.0,65.0,3.45,70.6
+2020-01-24 13:00:00,3.89,214.0,440.47,97.0,2.83,67.9
+2020-01-24 14:00:00,3.73,143.0,555.84,46.0,2.0,70.5
+2020-01-24 15:00:00,3.11,22.0,111.0,16.0,1.45,76.1
+2020-01-24 16:00:00,2.12,0.0,-0.0,0.0,1.52,78.95
+2020-01-24 17:00:00,1.09,0.0,-0.0,0.0,1.45,85.2
+2020-01-24 18:00:00,0.78,0.0,-0.0,0.0,1.24,88.5
+2020-01-24 19:00:00,0.59,0.0,-0.0,0.0,1.31,85.15
+2020-01-24 20:00:00,-0.27,0.0,-0.0,0.0,1.45,88.45
+2020-01-24 21:00:00,-0.85,0.0,-0.0,0.0,1.45,88.4
+2020-01-24 22:00:00,-1.28,0.0,-0.0,0.0,1.52,88.35
+2020-01-24 23:00:00,-1.34,0.0,-0.0,0.0,1.59,88.35
+2020-01-25 00:00:00,-1.58,0.0,-0.0,0.0,1.72,88.35
+2020-01-25 01:00:00,-1.69,0.0,-0.0,0.0,1.79,91.85
+2020-01-25 02:00:00,-1.39,0.0,-0.0,0.0,1.72,88.35
+2020-01-25 03:00:00,-1.05,0.0,-0.0,0.0,1.66,91.95
+2020-01-25 04:00:00,-0.42,0.0,-0.0,0.0,1.52,91.95
+2020-01-25 05:00:00,0.0,0.0,-0.0,0.0,1.38,95.6
+2020-01-25 06:00:00,0.19,0.0,-0.0,0.0,1.24,95.6
+2020-01-25 07:00:00,0.25,4.0,0.0,4.0,1.31,95.6
+2020-01-25 08:00:00,0.95,45.0,0.0,45.0,1.1,95.65
+2020-01-25 09:00:00,1.79,149.0,126.1,117.0,1.45,95.65
+2020-01-25 10:00:00,2.33,170.0,72.55,147.0,1.45,92.1
+2020-01-25 11:00:00,2.39,189.0,82.01,161.0,1.1,88.65
+2020-01-25 12:00:00,2.84,183.0,92.21,153.0,0.76,88.65
+2020-01-25 13:00:00,2.99,165.0,148.24,125.0,0.76,85.4
+2020-01-25 14:00:00,2.97,118.0,251.79,73.0,0.97,85.4
+2020-01-25 15:00:00,2.41,34.0,343.68,14.0,1.31,88.65
+2020-01-25 16:00:00,1.31,0.0,-0.0,0.0,1.59,95.65
+2020-01-25 17:00:00,0.59,0.0,-0.0,0.0,1.59,95.65
+2020-01-25 18:00:00,-0.24,0.0,-0.0,0.0,1.66,99.4
+2020-01-25 19:00:00,-0.68,0.0,-0.0,0.0,2.0,99.4
+2020-01-25 20:00:00,-1.2,0.0,-0.0,0.0,2.0,99.4
+2020-01-25 21:00:00,-1.72,0.0,-0.0,0.0,2.0,95.55
+2020-01-25 22:00:00,-2.03,0.0,-0.0,0.0,1.93,95.55
+2020-01-25 23:00:00,-2.11,0.0,-0.0,0.0,1.86,91.85
+2020-01-26 00:00:00,-2.03,0.0,-0.0,0.0,1.79,91.85
+2020-01-26 01:00:00,-2.36,0.0,-0.0,0.0,1.79,95.55
+2020-01-26 02:00:00,-2.57,0.0,-0.0,0.0,1.86,95.55
+2020-01-26 03:00:00,-2.4,0.0,-0.0,0.0,1.79,95.55
+2020-01-26 04:00:00,-2.41,0.0,-0.0,0.0,1.86,95.55
+2020-01-26 05:00:00,-2.36,0.0,-0.0,0.0,1.93,95.55
+2020-01-26 06:00:00,-2.6,0.0,-0.0,0.0,1.93,95.55
+2020-01-26 07:00:00,-2.9,7.0,0.0,7.0,1.93,91.85
+2020-01-26 08:00:00,-2.05,124.0,464.32,50.0,1.66,91.85
+2020-01-26 09:00:00,0.46,195.0,345.75,106.0,1.59,85.15
+2020-01-26 10:00:00,1.94,317.0,788.42,64.0,2.0,78.95
+2020-01-26 11:00:00,2.79,335.0,746.75,77.0,2.14,76.0
+2020-01-26 12:00:00,3.14,309.0,676.7,86.0,2.28,76.1
+2020-01-26 13:00:00,3.29,255.0,700.44,63.0,2.34,76.1
+2020-01-26 14:00:00,2.96,127.0,306.02,71.0,1.93,79.1
+2020-01-26 15:00:00,2.17,30.0,176.3,19.0,1.93,85.3
+2020-01-26 16:00:00,1.17,0.0,-0.0,0.0,1.93,92.05
+2020-01-26 17:00:00,0.47,0.0,-0.0,0.0,1.79,92.0
+2020-01-26 18:00:00,-0.36,0.0,-0.0,0.0,1.79,95.6
+2020-01-26 19:00:00,-0.86,0.0,-0.0,0.0,1.45,95.6
+2020-01-26 20:00:00,-1.47,0.0,-0.0,0.0,1.45,95.6
+2020-01-26 21:00:00,-1.5,0.0,-0.0,0.0,1.38,95.6
+2020-01-26 22:00:00,-1.58,0.0,-0.0,0.0,1.31,95.6
+2020-01-26 23:00:00,-1.26,0.0,-0.0,0.0,1.17,95.6
+2020-01-27 00:00:00,-1.07,0.0,-0.0,0.0,1.03,91.95
+2020-01-27 01:00:00,-1.0,0.0,-0.0,0.0,0.97,91.95
+2020-01-27 02:00:00,-0.94,0.0,-0.0,0.0,0.9,91.95
+2020-01-27 03:00:00,-0.92,0.0,-0.0,0.0,0.83,95.6
+2020-01-27 04:00:00,-1.02,0.0,-0.0,0.0,0.9,95.6
+2020-01-27 05:00:00,-0.93,0.0,-0.0,0.0,0.9,95.6
+2020-01-27 06:00:00,-0.89,0.0,-0.0,0.0,0.97,95.6
+2020-01-27 07:00:00,-1.24,8.0,0.0,8.0,0.69,95.6
+2020-01-27 08:00:00,-1.05,88.0,116.68,69.0,0.69,91.95
+2020-01-27 09:00:00,-0.01,61.0,0.0,61.0,0.9,88.45
+2020-01-27 10:00:00,0.82,134.0,15.39,129.0,1.1,88.5
+2020-01-27 11:00:00,1.34,170.0,42.9,155.0,1.59,88.55
+2020-01-27 12:00:00,1.54,110.0,3.0,109.0,2.14,85.25
+2020-01-27 13:00:00,1.37,77.0,0.0,77.0,2.28,85.25
+2020-01-27 14:00:00,1.27,49.0,0.0,49.0,2.21,92.05
+2020-01-27 15:00:00,0.89,15.0,0.0,15.0,1.93,92.05
+2020-01-27 16:00:00,0.35,0.0,-0.0,0.0,1.72,95.65
+2020-01-27 17:00:00,0.0,0.0,-0.0,0.0,2.07,95.6
+2020-01-27 18:00:00,-0.3,0.0,-0.0,0.0,2.28,99.4
+2020-01-27 19:00:00,-0.78,0.0,-0.0,0.0,2.62,99.4
+2020-01-27 20:00:00,-1.13,0.0,-0.0,0.0,2.76,91.95
+2020-01-27 21:00:00,-1.35,0.0,-0.0,0.0,2.41,95.6
+2020-01-27 22:00:00,-1.49,0.0,-0.0,0.0,2.0,91.9
+2020-01-27 23:00:00,-1.56,0.0,-0.0,0.0,2.07,91.9
+2020-01-28 00:00:00,-1.68,0.0,-0.0,0.0,2.14,95.55
+2020-01-28 01:00:00,-1.87,0.0,-0.0,0.0,2.14,91.85
+2020-01-28 02:00:00,-1.92,0.0,-0.0,0.0,1.93,91.85
+2020-01-28 03:00:00,-1.91,0.0,-0.0,0.0,1.86,91.85
+2020-01-28 04:00:00,-1.93,0.0,-0.0,0.0,1.86,91.85
+2020-01-28 05:00:00,-1.89,0.0,-0.0,0.0,1.79,91.85
+2020-01-28 06:00:00,-1.9,0.0,-0.0,0.0,1.66,91.85
+2020-01-28 07:00:00,-1.71,10.0,0.0,10.0,1.79,95.55
+2020-01-28 08:00:00,-1.46,66.0,24.04,62.0,1.86,91.9
+2020-01-28 09:00:00,-1.11,151.0,105.67,123.0,2.14,88.4
+2020-01-28 10:00:00,-0.55,274.0,434.74,131.0,2.34,88.45
+2020-01-28 11:00:00,0.07,69.0,0.0,69.0,2.48,85.1
+2020-01-28 12:00:00,0.49,126.0,5.91,124.0,2.48,78.75
+2020-01-28 13:00:00,0.72,176.0,152.0,133.0,2.41,78.75
+2020-01-28 14:00:00,0.72,109.0,130.39,84.0,2.28,75.7
+2020-01-28 15:00:00,0.52,42.0,310.04,20.0,2.14,75.7
+2020-01-28 16:00:00,-0.49,0.0,-0.0,0.0,1.86,81.75
+2020-01-28 17:00:00,-1.5,0.0,-0.0,0.0,1.79,88.35
+2020-01-28 18:00:00,-2.45,0.0,-0.0,0.0,1.45,95.55
+2020-01-28 19:00:00,-3.38,0.0,-0.0,0.0,1.86,95.55
+2020-01-28 20:00:00,-3.29,0.0,-0.0,0.0,2.0,99.4
+2020-01-28 21:00:00,-2.96,0.0,-0.0,0.0,2.21,95.55
+2020-01-28 22:00:00,-2.65,0.0,-0.0,0.0,2.48,95.55
+2020-01-28 23:00:00,-2.52,0.0,-0.0,0.0,2.41,95.55
+2020-01-29 00:00:00,-2.61,0.0,-0.0,0.0,2.48,95.55
+2020-01-29 01:00:00,-2.8,0.0,-0.0,0.0,2.21,91.85
+2020-01-29 02:00:00,-2.73,0.0,-0.0,0.0,1.86,95.55
+2020-01-29 03:00:00,-2.56,0.0,-0.0,0.0,1.79,95.55
+2020-01-29 04:00:00,-2.43,0.0,-0.0,0.0,1.93,95.55
+2020-01-29 05:00:00,-2.28,0.0,-0.0,0.0,2.07,95.55
+2020-01-29 06:00:00,-2.17,0.0,-0.0,0.0,2.0,95.55
+2020-01-29 07:00:00,-2.07,5.0,0.0,5.0,2.48,95.55
+2020-01-29 08:00:00,-1.84,69.0,29.4,64.0,3.31,91.85
+2020-01-29 09:00:00,-1.65,59.0,0.0,59.0,3.66,84.95
+2020-01-29 10:00:00,-1.24,61.0,0.0,61.0,3.17,84.95
+2020-01-29 11:00:00,-0.58,65.0,0.0,65.0,2.97,78.6
+2020-01-29 12:00:00,-0.33,56.0,0.0,56.0,2.76,78.6
+2020-01-29 13:00:00,-0.26,48.0,0.0,48.0,2.62,78.6
+2020-01-29 14:00:00,-0.33,33.0,0.0,33.0,2.55,81.75
+2020-01-29 15:00:00,-0.71,16.0,0.0,16.0,2.14,85.0
+2020-01-29 16:00:00,-1.22,0.0,-0.0,0.0,2.0,88.35
+2020-01-29 17:00:00,-1.5,0.0,-0.0,0.0,2.07,88.35
+2020-01-29 18:00:00,-1.69,0.0,-0.0,0.0,2.07,91.85
+2020-01-29 19:00:00,-2.23,0.0,-0.0,0.0,2.83,91.85
+2020-01-29 20:00:00,-2.27,0.0,-0.0,0.0,2.55,91.85
+2020-01-29 21:00:00,-2.37,0.0,-0.0,0.0,2.28,91.85
+2020-01-29 22:00:00,-2.53,0.0,-0.0,0.0,2.21,91.85
+2020-01-29 23:00:00,-2.62,0.0,-0.0,0.0,1.86,88.25
+2020-01-30 00:00:00,-2.69,0.0,-0.0,0.0,2.21,88.25
+2020-01-30 01:00:00,-2.84,0.0,-0.0,0.0,2.14,88.25
+2020-01-30 02:00:00,-3.02,0.0,-0.0,0.0,1.86,88.25
+2020-01-30 03:00:00,-3.01,0.0,-0.0,0.0,2.0,84.85
+2020-01-30 04:00:00,-3.12,0.0,-0.0,0.0,2.14,88.25
+2020-01-30 05:00:00,-3.3,0.0,-0.0,0.0,2.28,88.25
+2020-01-30 06:00:00,-3.14,0.0,-0.0,0.0,2.41,84.85
+2020-01-30 07:00:00,-3.02,6.0,0.0,6.0,2.69,84.85
+2020-01-30 08:00:00,-2.9,71.0,28.76,66.0,2.62,81.5
+2020-01-30 09:00:00,-2.71,44.0,0.0,44.0,2.48,81.5
+2020-01-30 10:00:00,-2.3,77.0,0.0,77.0,2.48,81.5
+2020-01-30 11:00:00,-2.08,88.0,0.0,88.0,2.41,75.3
+2020-01-30 12:00:00,-1.72,199.0,95.06,166.0,2.34,78.35
+2020-01-30 13:00:00,-1.53,56.0,0.0,56.0,2.28,75.35
+2020-01-30 14:00:00,-1.55,44.0,0.0,44.0,2.21,75.35
+2020-01-30 15:00:00,-1.62,20.0,0.0,20.0,2.14,78.45
+2020-01-30 16:00:00,-1.86,0.0,-0.0,0.0,1.93,81.55
+2020-01-30 17:00:00,-2.03,0.0,-0.0,0.0,1.72,84.85
+2020-01-30 18:00:00,-2.28,0.0,-0.0,0.0,1.52,88.25
+2020-01-30 19:00:00,-2.33,0.0,-0.0,0.0,2.28,88.25
+2020-01-30 20:00:00,-2.32,0.0,-0.0,0.0,2.0,91.85
+2020-01-30 21:00:00,-2.24,0.0,-0.0,0.0,1.24,95.55
+2020-01-30 22:00:00,-2.16,0.0,-0.0,0.0,0.97,91.85
+2020-01-30 23:00:00,-2.04,0.0,-0.0,0.0,1.03,91.85
+2020-01-31 00:00:00,-1.91,0.0,-0.0,0.0,1.38,95.55
+2020-01-31 01:00:00,-1.13,0.0,-0.0,0.0,1.59,95.6
+2020-01-31 02:00:00,-0.91,0.0,-0.0,0.0,1.79,95.6
+2020-01-31 03:00:00,-0.79,0.0,-0.0,0.0,1.93,95.6
+2020-01-31 04:00:00,-0.72,0.0,-0.0,0.0,1.93,99.4
+2020-01-31 05:00:00,-0.7,0.0,-0.0,0.0,2.28,95.6
+2020-01-31 06:00:00,-0.74,0.0,-0.0,0.0,2.41,95.6
+2020-01-31 07:00:00,-0.7,9.0,0.0,9.0,2.0,91.95
+2020-01-31 08:00:00,-0.53,83.0,56.26,73.0,3.03,85.05
+2020-01-31 09:00:00,-0.54,87.0,0.0,87.0,3.45,88.45
+2020-01-31 10:00:00,-0.16,64.0,0.0,64.0,3.52,81.75
+2020-01-31 11:00:00,-0.03,72.0,0.0,72.0,3.52,78.65
+2020-01-31 12:00:00,0.13,68.0,0.0,68.0,3.31,78.65
+2020-01-31 13:00:00,0.28,153.0,64.07,134.0,3.31,78.65
+2020-01-31 14:00:00,0.24,53.0,0.0,53.0,3.31,78.65
+2020-01-31 15:00:00,-0.3,29.0,23.75,27.0,2.55,81.75
+2020-01-31 16:00:00,-3.77,0.0,-0.0,0.0,2.26,87.1
+2020-01-31 17:00:00,-3.11,0.0,-0.0,0.0,2.32,87.42
+2020-01-31 18:00:00,-2.46,0.0,-0.0,0.0,2.39,87.74
+2020-01-31 19:00:00,-1.8,0.0,-0.0,0.0,2.46,88.05
+2020-01-31 20:00:00,-1.14,0.0,-0.0,0.0,2.52,88.37
+2020-01-31 21:00:00,-0.49,0.0,-0.0,0.0,2.59,88.68
+2020-01-31 22:00:00,0.17,0.0,-0.0,0.0,2.66,89.0
+2020-01-31 23:00:00,0.82,0.0,-0.0,0.0,2.73,89.32
+2020-02-01 00:00:00,1.48,0.0,-0.0,0.0,2.79,89.63
+2020-02-01 01:00:00,2.13,0.0,-0.0,0.0,2.86,89.95
+2020-02-01 02:00:00,2.79,0.0,-0.0,0.0,2.93,90.27
+2020-02-01 03:00:00,3.44,0.0,-0.0,0.0,2.99,90.58
+2020-02-01 04:00:00,4.1,0.0,-0.0,0.0,3.06,90.9
+2020-02-01 05:00:00,4.76,0.0,-0.0,0.0,3.13,91.21
+2020-02-01 06:00:00,5.41,0.0,-0.0,0.0,3.19,91.53
+2020-02-01 07:00:00,6.07,3.0,0.0,3.0,3.26,91.85
+2020-02-01 08:00:00,3.68,111.0,192.62,76.0,1.66,95.7
+2020-02-01 09:00:00,3.96,120.0,24.89,113.0,2.14,92.2
+2020-02-01 10:00:00,4.43,151.0,23.12,143.0,2.34,85.55
+2020-02-01 11:00:00,4.72,177.0,40.36,162.0,2.34,79.3
+2020-02-01 12:00:00,5.17,161.0,30.87,150.0,2.41,68.1
+2020-02-01 13:00:00,5.37,97.0,3.32,96.0,2.28,65.55
+2020-02-01 14:00:00,5.39,63.0,4.76,62.0,2.0,63.05
+2020-02-01 15:00:00,5.11,31.0,33.82,28.0,1.66,63.05
+2020-02-01 16:00:00,4.29,0.0,-0.0,0.0,1.86,67.9
+2020-02-01 17:00:00,3.41,0.0,-0.0,0.0,2.14,70.5
+2020-02-01 18:00:00,2.96,0.0,-0.0,0.0,2.34,73.2
+2020-02-01 19:00:00,2.13,0.0,-0.0,0.0,2.28,78.95
+2020-02-01 20:00:00,1.48,0.0,-0.0,0.0,2.48,82.0
+2020-02-01 21:00:00,0.97,0.0,-0.0,0.0,2.76,81.95
+2020-02-01 22:00:00,0.54,0.0,-0.0,0.0,2.83,81.9
+2020-02-01 23:00:00,0.23,0.0,-0.0,0.0,2.83,81.8
+2020-02-02 00:00:00,0.02,0.0,-0.0,0.0,2.9,81.8
+2020-02-02 01:00:00,0.08,0.0,-0.0,0.0,2.9,81.8
+2020-02-02 02:00:00,0.07,0.0,-0.0,0.0,2.83,85.1
+2020-02-02 03:00:00,-0.08,0.0,-0.0,0.0,2.69,85.1
+2020-02-02 04:00:00,-0.35,0.0,-0.0,0.0,2.55,88.45
+2020-02-02 05:00:00,-0.73,0.0,-0.0,0.0,2.41,88.4
+2020-02-02 06:00:00,-1.12,0.0,-0.0,0.0,2.41,88.4
+2020-02-02 07:00:00,-1.26,31.0,241.46,17.0,2.55,88.35
+2020-02-02 08:00:00,0.05,152.0,532.92,53.0,2.62,85.1
+2020-02-02 09:00:00,1.92,259.0,637.34,77.0,3.17,78.95
+2020-02-02 10:00:00,3.24,330.0,676.07,93.0,3.59,70.4
+2020-02-02 11:00:00,4.3,357.0,677.62,102.0,3.72,60.4
+2020-02-02 12:00:00,4.89,337.0,648.02,103.0,3.93,55.95
+2020-02-02 13:00:00,5.5,151.0,52.3,135.0,4.48,46.1
+2020-02-02 14:00:00,5.45,42.0,0.0,42.0,3.86,48.0
+2020-02-02 15:00:00,5.0,10.0,0.0,10.0,3.1,51.8
+2020-02-02 16:00:00,4.41,0.0,-0.0,0.0,2.76,53.8
+2020-02-02 17:00:00,4.06,0.0,-0.0,0.0,2.55,58.05
+2020-02-02 18:00:00,3.52,0.0,-0.0,0.0,2.41,62.7
+2020-02-02 19:00:00,2.19,0.0,-0.0,0.0,2.14,73.0
+2020-02-02 20:00:00,1.33,0.0,-0.0,0.0,2.41,78.8
+2020-02-02 21:00:00,0.82,0.0,-0.0,0.0,2.55,85.15
+2020-02-02 22:00:00,0.71,0.0,-0.0,0.0,2.62,88.5
+2020-02-02 23:00:00,1.03,0.0,-0.0,0.0,2.69,85.2
+2020-02-03 00:00:00,1.38,0.0,-0.0,0.0,2.55,85.25
+2020-02-03 01:00:00,1.34,0.0,-0.0,0.0,2.41,88.55
+2020-02-03 02:00:00,1.28,0.0,-0.0,0.0,2.41,92.05
+2020-02-03 03:00:00,1.32,0.0,-0.0,0.0,2.55,92.05
+2020-02-03 04:00:00,1.3,0.0,-0.0,0.0,2.62,92.05
+2020-02-03 05:00:00,1.33,0.0,-0.0,0.0,2.76,92.05
+2020-02-03 06:00:00,1.37,0.0,-0.0,0.0,2.76,88.6
+2020-02-03 07:00:00,1.48,16.0,16.16,15.0,2.62,92.05
+2020-02-03 08:00:00,1.39,84.0,42.12,76.0,2.28,92.05
+2020-02-03 09:00:00,1.68,144.0,55.18,128.0,2.76,95.65
+2020-02-03 10:00:00,1.91,252.0,242.17,166.0,3.1,88.65
+2020-02-03 11:00:00,2.58,57.0,0.0,57.0,3.59,76.0
+2020-02-03 12:00:00,3.08,127.0,2.73,126.0,3.31,70.4
+2020-02-03 13:00:00,3.19,72.0,0.0,72.0,3.03,70.4
+2020-02-03 14:00:00,2.87,41.0,0.0,41.0,2.9,76.0
+2020-02-03 15:00:00,1.99,18.0,0.0,18.0,2.21,82.05
+2020-02-03 16:00:00,1.05,0.0,-0.0,0.0,1.79,88.55
+2020-02-03 17:00:00,0.06,0.0,-0.0,0.0,2.0,92.0
+2020-02-03 18:00:00,-0.56,0.0,-0.0,0.0,1.79,91.95
+2020-02-03 19:00:00,-1.51,0.0,-0.0,0.0,1.59,95.6
+2020-02-03 20:00:00,-2.04,0.0,-0.0,0.0,1.38,95.55
+2020-02-03 21:00:00,-2.11,0.0,-0.0,0.0,1.31,95.55
+2020-02-03 22:00:00,-2.18,0.0,-0.0,0.0,1.24,95.55
+2020-02-03 23:00:00,-1.7,0.0,-0.0,0.0,1.03,99.4
+2020-02-04 00:00:00,-1.09,0.0,-0.0,0.0,0.83,91.95
+2020-02-04 01:00:00,-0.93,0.0,-0.0,0.0,0.69,91.95
+2020-02-04 02:00:00,-0.63,0.0,-0.0,0.0,0.55,88.45
+2020-02-04 03:00:00,-0.76,0.0,-0.0,0.0,0.62,91.95
+2020-02-04 04:00:00,-1.41,0.0,-0.0,0.0,0.9,91.9
+2020-02-04 05:00:00,-1.38,0.0,-0.0,0.0,0.9,95.6
+2020-02-04 06:00:00,-1.19,0.0,-0.0,0.0,0.9,95.6
+2020-02-04 07:00:00,-0.89,20.0,15.18,19.0,1.79,99.4
+2020-02-04 08:00:00,-0.42,39.0,0.0,39.0,2.07,91.95
+2020-02-04 09:00:00,0.0,68.0,0.0,68.0,2.28,88.45
+2020-02-04 10:00:00,0.56,58.0,0.0,58.0,2.21,85.15
+2020-02-04 11:00:00,0.88,87.0,0.0,87.0,2.21,81.95
+2020-02-04 12:00:00,1.32,48.0,0.0,48.0,2.07,78.8
+2020-02-04 13:00:00,1.78,56.0,0.0,56.0,2.0,72.95
+2020-02-04 14:00:00,1.66,40.0,0.0,40.0,2.34,70.1
+2020-02-04 15:00:00,0.97,30.0,9.76,29.0,2.21,70.05
+2020-02-04 16:00:00,0.19,0.0,-0.0,0.0,2.28,75.6
+2020-02-04 17:00:00,-0.64,0.0,-0.0,0.0,2.0,75.55
+2020-02-04 18:00:00,-1.2,0.0,-0.0,0.0,1.66,81.65
+2020-02-04 19:00:00,-1.66,0.0,-0.0,0.0,1.52,88.3
+2020-02-04 20:00:00,-1.88,0.0,-0.0,0.0,1.24,88.3
+2020-02-04 21:00:00,-1.76,0.0,-0.0,0.0,1.24,88.3
+2020-02-04 22:00:00,-1.79,0.0,-0.0,0.0,1.24,88.3
+2020-02-04 23:00:00,-1.49,0.0,-0.0,0.0,1.31,88.35
+2020-02-05 00:00:00,-1.4,0.0,-0.0,0.0,1.31,88.35
+2020-02-05 01:00:00,-1.25,0.0,-0.0,0.0,1.31,91.9
+2020-02-05 02:00:00,-1.09,0.0,-0.0,0.0,1.86,91.95
+2020-02-05 03:00:00,-1.35,0.0,-0.0,0.0,1.52,99.4
+2020-02-05 04:00:00,-1.45,0.0,-0.0,0.0,1.72,99.4
+2020-02-05 05:00:00,-1.79,0.0,-0.0,0.0,1.86,99.4
+2020-02-05 06:00:00,-2.21,0.0,-0.0,0.0,2.07,95.55
+2020-02-05 07:00:00,-2.57,22.0,28.58,20.0,1.52,91.85
+2020-02-05 08:00:00,-2.19,149.0,372.76,75.0,2.41,91.85
+2020-02-05 09:00:00,-1.26,212.0,250.86,137.0,2.55,81.65
+2020-02-05 10:00:00,-0.23,278.0,310.02,165.0,2.83,69.75
+2020-02-05 11:00:00,0.22,117.0,0.0,117.0,2.9,67.1
+2020-02-05 12:00:00,0.4,184.0,42.6,168.0,2.83,64.55
+2020-02-05 13:00:00,0.49,135.0,18.72,129.0,2.76,62.0
+2020-02-05 14:00:00,0.08,142.0,174.77,102.0,2.55,67.1
+2020-02-05 15:00:00,-0.36,35.0,18.66,33.0,2.34,69.75
+2020-02-05 16:00:00,-1.22,0.0,-0.0,0.0,2.07,75.35
+2020-02-05 17:00:00,-2.21,0.0,-0.0,0.0,2.07,78.35
+2020-02-05 18:00:00,-2.88,0.0,-0.0,0.0,2.14,78.3
+2020-02-05 19:00:00,-3.18,0.0,-0.0,0.0,2.07,81.45
+2020-02-05 20:00:00,-3.19,0.0,-0.0,0.0,2.28,72.1
+2020-02-05 21:00:00,-3.48,0.0,-0.0,0.0,2.21,69.25
+2020-02-05 22:00:00,-3.72,0.0,-0.0,0.0,2.07,69.15
+2020-02-05 23:00:00,-4.0,0.0,-0.0,0.0,2.0,66.35
+2020-02-06 00:00:00,-4.24,0.0,-0.0,0.0,1.79,69.05
+2020-02-06 01:00:00,-4.95,0.0,-0.0,0.0,1.66,68.95
+2020-02-06 02:00:00,-5.4,0.0,-0.0,0.0,1.59,71.75
+2020-02-06 03:00:00,-6.05,0.0,-0.0,0.0,1.52,74.7
+2020-02-06 04:00:00,-6.44,0.0,-0.0,0.0,1.45,77.75
+2020-02-06 05:00:00,-6.64,0.0,-0.0,0.0,1.52,77.75
+2020-02-06 06:00:00,-6.86,0.0,-0.0,0.0,1.59,81.0
+2020-02-06 07:00:00,-5.73,38.0,175.24,25.0,1.59,74.7
+2020-02-06 08:00:00,-4.23,161.0,443.47,71.0,1.66,69.05
+2020-02-06 09:00:00,-3.1,269.0,563.24,98.0,2.28,61.35
+2020-02-06 10:00:00,-1.92,342.0,617.4,114.0,2.83,58.95
+2020-02-06 11:00:00,-1.07,378.0,669.97,113.0,2.9,59.2
+2020-02-06 12:00:00,-0.34,330.0,486.13,145.0,2.9,56.95
+2020-02-06 13:00:00,0.11,290.0,565.52,106.0,2.83,57.1
+2020-02-06 14:00:00,0.24,194.0,496.31,78.0,2.76,57.1
+2020-02-06 15:00:00,-0.27,75.0,348.58,36.0,2.21,59.35
+2020-02-06 16:00:00,-1.44,0.0,-0.0,0.0,2.07,64.1
+2020-02-06 17:00:00,-2.36,0.0,-0.0,0.0,2.07,66.65
+2020-02-06 18:00:00,-2.9,0.0,-0.0,0.0,2.14,69.35
+2020-02-06 19:00:00,-3.14,0.0,-0.0,0.0,2.55,69.35
+2020-02-06 20:00:00,-3.12,0.0,-0.0,0.0,2.76,69.35
+2020-02-06 21:00:00,-3.16,0.0,-0.0,0.0,2.83,69.35
+2020-02-06 22:00:00,-3.08,0.0,-0.0,0.0,2.76,69.35
+2020-02-06 23:00:00,-3.2,0.0,-0.0,0.0,2.55,75.1
+2020-02-07 00:00:00,-3.31,0.0,-0.0,0.0,2.14,78.2
+2020-02-07 01:00:00,-3.52,0.0,-0.0,0.0,2.14,78.2
+2020-02-07 02:00:00,-3.14,0.0,-0.0,0.0,2.14,78.3
+2020-02-07 03:00:00,-3.1,0.0,-0.0,0.0,2.07,78.3
+2020-02-07 04:00:00,-2.97,0.0,-0.0,0.0,2.0,81.5
+2020-02-07 05:00:00,-2.85,0.0,-0.0,0.0,1.93,84.85
+2020-02-07 06:00:00,-2.55,0.0,-0.0,0.0,1.79,84.85
+2020-02-07 07:00:00,-3.53,36.0,114.7,27.0,1.72,84.8
+2020-02-07 08:00:00,-2.59,133.0,212.09,89.0,1.45,84.85
+2020-02-07 09:00:00,-1.09,237.0,353.54,128.0,1.45,81.7
+2020-02-07 10:00:00,0.05,307.0,416.94,151.0,1.79,72.65
+2020-02-07 11:00:00,1.18,373.0,639.19,117.0,1.31,67.3
+2020-02-07 12:00:00,1.52,346.0,570.6,126.0,1.03,67.4
+2020-02-07 13:00:00,1.59,286.0,526.73,112.0,1.66,70.1
+2020-02-07 14:00:00,1.44,156.0,217.93,104.0,2.0,70.1
+2020-02-07 15:00:00,0.93,48.0,51.45,42.0,2.0,72.85
+2020-02-07 16:00:00,-0.25,0.0,-0.0,0.0,1.93,81.75
+2020-02-07 17:00:00,-1.05,0.0,-0.0,0.0,1.79,85.0
+2020-02-07 18:00:00,-1.56,0.0,-0.0,0.0,1.59,84.95
+2020-02-07 19:00:00,-2.24,0.0,-0.0,0.0,1.45,81.55
+2020-02-07 20:00:00,-2.8,0.0,-0.0,0.0,1.31,81.5
+2020-02-07 21:00:00,-3.41,0.0,-0.0,0.0,1.17,84.8
+2020-02-07 22:00:00,-3.83,0.0,-0.0,0.0,1.1,88.2
+2020-02-07 23:00:00,-3.93,0.0,-0.0,0.0,1.17,88.2
+2020-02-08 00:00:00,-3.56,0.0,-0.0,0.0,1.31,84.8
+2020-02-08 01:00:00,-3.62,0.0,-0.0,0.0,1.38,84.8
+2020-02-08 02:00:00,-3.64,0.0,-0.0,0.0,1.52,84.8
+2020-02-08 03:00:00,-3.5,0.0,-0.0,0.0,1.66,88.25
+2020-02-08 04:00:00,-3.54,0.0,-0.0,0.0,1.79,88.25
+2020-02-08 05:00:00,-3.43,0.0,-0.0,0.0,1.79,88.25
+2020-02-08 06:00:00,-3.36,0.0,-0.0,0.0,1.59,88.25
+2020-02-08 07:00:00,-3.52,5.0,0.0,5.0,1.38,88.25
+2020-02-08 08:00:00,-3.25,81.0,18.86,77.0,1.45,88.25
+2020-02-08 09:00:00,-2.81,106.0,3.19,105.0,1.52,81.5
+2020-02-08 10:00:00,-2.41,108.0,0.0,108.0,1.45,78.35
+2020-02-08 11:00:00,-1.85,88.0,0.0,88.0,1.38,78.35
+2020-02-08 12:00:00,-1.44,78.0,0.0,78.0,1.31,75.35
+2020-02-08 13:00:00,-1.44,98.0,0.0,98.0,1.45,72.4
+2020-02-08 14:00:00,-1.46,68.0,0.0,68.0,1.31,72.4
+2020-02-08 15:00:00,-1.76,28.0,0.0,28.0,1.45,75.3
+2020-02-08 16:00:00,-2.18,0.0,-0.0,0.0,1.38,75.3
+2020-02-08 17:00:00,-2.46,0.0,-0.0,0.0,1.31,78.35
+2020-02-08 18:00:00,-2.68,0.0,-0.0,0.0,1.03,81.5
+2020-02-08 19:00:00,-2.83,0.0,-0.0,0.0,0.76,81.5
+2020-02-08 20:00:00,-2.97,0.0,-0.0,0.0,0.48,81.5
+2020-02-08 21:00:00,-2.97,0.0,-0.0,0.0,0.55,81.5
+2020-02-08 22:00:00,-2.92,0.0,-0.0,0.0,0.55,81.5
+2020-02-08 23:00:00,-3.02,0.0,-0.0,0.0,0.62,81.5
+2020-02-09 00:00:00,-3.1,0.0,-0.0,0.0,0.83,81.5
+2020-02-09 01:00:00,-2.92,0.0,-0.0,0.0,1.1,84.85
+2020-02-09 02:00:00,-2.65,0.0,-0.0,0.0,1.17,78.35
+2020-02-09 03:00:00,-3.21,0.0,-0.0,0.0,1.31,81.45
+2020-02-09 04:00:00,-3.59,0.0,-0.0,0.0,1.45,81.45
+2020-02-09 05:00:00,-3.4,0.0,-0.0,0.0,1.59,81.45
+2020-02-09 06:00:00,-3.11,0.0,-0.0,0.0,1.72,78.3
+2020-02-09 07:00:00,-2.59,36.0,68.72,30.0,1.59,88.3
+2020-02-09 08:00:00,-1.65,162.0,369.12,82.0,1.59,81.65
+2020-02-09 09:00:00,-0.56,294.0,669.89,81.0,1.86,75.55
+2020-02-09 10:00:00,0.84,365.0,689.95,100.0,1.93,69.95
+2020-02-09 11:00:00,2.09,402.0,747.67,95.0,2.07,62.35
+2020-02-09 12:00:00,2.73,386.0,753.07,88.0,1.93,57.7
+2020-02-09 13:00:00,2.77,317.0,672.7,88.0,1.72,57.7
+2020-02-09 14:00:00,2.88,219.0,627.78,63.0,1.59,55.55
+2020-02-09 15:00:00,2.05,87.0,372.41,40.0,1.66,64.9
+2020-02-09 16:00:00,0.66,0.0,-0.0,0.0,2.21,72.75
+2020-02-09 17:00:00,-0.44,0.0,-0.0,0.0,2.28,78.6
+2020-02-09 18:00:00,-0.75,0.0,-0.0,0.0,2.28,81.7
+2020-02-09 19:00:00,-1.7,0.0,-0.0,0.0,2.07,88.3
+2020-02-09 20:00:00,-1.8,0.0,-0.0,0.0,2.0,88.3
+2020-02-09 21:00:00,-1.92,0.0,-0.0,0.0,1.86,88.3
+2020-02-09 22:00:00,-2.1,0.0,-0.0,0.0,1.66,88.3
+2020-02-09 23:00:00,-2.21,0.0,-0.0,0.0,1.52,88.3
+2020-02-10 00:00:00,-2.5,0.0,-0.0,0.0,1.45,88.3
+2020-02-10 01:00:00,-2.53,0.0,-0.0,0.0,1.31,88.3
+2020-02-10 02:00:00,-2.27,0.0,-0.0,0.0,1.17,91.85
+2020-02-10 03:00:00,-2.63,0.0,-0.0,0.0,1.24,88.3
+2020-02-10 04:00:00,-2.43,0.0,-0.0,0.0,1.17,91.85
+2020-02-10 05:00:00,-2.59,0.0,-0.0,0.0,1.24,88.3
+2020-02-10 06:00:00,-2.33,0.0,-0.0,0.0,1.24,91.85
+2020-02-10 07:00:00,-2.23,15.0,0.0,15.0,0.97,91.85
+2020-02-10 08:00:00,-0.81,51.0,0.0,51.0,0.83,88.4
+2020-02-10 09:00:00,0.6,96.0,0.0,96.0,1.03,75.7
+2020-02-10 10:00:00,1.44,135.0,2.57,134.0,1.31,67.4
+2020-02-10 11:00:00,2.25,148.0,4.81,146.0,1.59,62.35
+2020-02-10 12:00:00,2.29,173.0,19.96,165.0,1.59,62.35
+2020-02-10 13:00:00,2.71,101.0,0.0,101.0,1.52,60.05
+2020-02-10 14:00:00,2.71,100.0,19.73,95.0,1.24,60.05
+2020-02-10 15:00:00,2.42,50.0,30.53,46.0,0.48,62.5
+2020-02-10 16:00:00,1.98,0.0,-0.0,0.0,0.34,70.2
+2020-02-10 17:00:00,0.9,0.0,-0.0,0.0,0.9,70.05
+2020-02-10 18:00:00,-0.47,0.0,-0.0,0.0,1.45,78.6
+2020-02-10 19:00:00,-0.75,0.0,-0.0,0.0,1.38,85.0
+2020-02-10 20:00:00,-0.71,0.0,-0.0,0.0,1.52,85.0
+2020-02-10 21:00:00,-0.87,0.0,-0.0,0.0,1.66,85.0
+2020-02-10 22:00:00,-1.25,0.0,-0.0,0.0,1.72,88.35
+2020-02-10 23:00:00,-1.55,0.0,-0.0,0.0,1.79,88.35
+2020-02-11 00:00:00,-2.08,0.0,-0.0,0.0,1.86,88.3
+2020-02-11 01:00:00,-2.06,0.0,-0.0,0.0,1.93,91.85
+2020-02-11 02:00:00,-1.8,0.0,-0.0,0.0,2.0,91.85
+2020-02-11 03:00:00,-1.79,0.0,-0.0,0.0,2.07,91.85
+2020-02-11 04:00:00,-2.02,0.0,-0.0,0.0,2.21,88.3
+2020-02-11 05:00:00,-2.14,0.0,-0.0,0.0,2.28,88.3
+2020-02-11 06:00:00,-1.94,0.0,-0.0,0.0,2.41,88.3
+2020-02-11 07:00:00,-1.06,56.0,248.73,32.0,2.97,85.0
+2020-02-11 08:00:00,0.27,197.0,622.98,56.0,2.83,85.1
+2020-02-11 09:00:00,1.9,250.0,341.57,138.0,3.79,73.0
+2020-02-11 10:00:00,2.74,260.0,177.54,190.0,4.34,65.0
+2020-02-11 11:00:00,3.52,405.0,715.09,104.0,4.83,57.95
+2020-02-11 12:00:00,3.69,186.0,29.55,174.0,4.76,57.95
+2020-02-11 13:00:00,3.65,158.0,31.37,147.0,4.07,62.7
+2020-02-11 14:00:00,3.24,45.0,0.0,45.0,3.86,70.4
+2020-02-11 15:00:00,2.84,45.0,14.72,43.0,3.72,73.1
+2020-02-11 16:00:00,2.51,0.0,-0.0,0.0,3.31,76.0
+2020-02-11 17:00:00,2.32,0.0,-0.0,0.0,3.17,78.95
+2020-02-11 18:00:00,2.18,0.0,-0.0,0.0,3.03,78.95
+2020-02-11 19:00:00,2.02,0.0,-0.0,0.0,2.83,78.95
+2020-02-11 20:00:00,1.79,0.0,-0.0,0.0,2.9,82.0
+2020-02-11 21:00:00,1.79,0.0,-0.0,0.0,2.97,82.0
+2020-02-11 22:00:00,1.61,0.0,-0.0,0.0,2.9,85.25
+2020-02-11 23:00:00,1.53,0.0,-0.0,0.0,2.97,85.25
+2020-02-12 00:00:00,1.29,0.0,-0.0,0.0,3.1,88.55
+2020-02-12 01:00:00,1.35,0.0,-0.0,0.0,3.03,92.05
+2020-02-12 02:00:00,0.92,0.0,-0.0,0.0,2.83,88.55
+2020-02-12 03:00:00,0.49,0.0,-0.0,0.0,2.62,88.5
+2020-02-12 04:00:00,0.01,0.0,-0.0,0.0,2.69,88.45
+2020-02-12 05:00:00,-0.06,0.0,-0.0,0.0,2.76,88.45
+2020-02-12 06:00:00,0.01,0.0,-0.0,0.0,2.9,88.45
+2020-02-12 07:00:00,0.24,62.0,266.78,35.0,2.69,92.0
+2020-02-12 08:00:00,1.3,205.0,640.02,57.0,2.76,88.55
+2020-02-12 09:00:00,2.28,192.0,108.12,156.0,4.07,78.95
+2020-02-12 10:00:00,2.55,233.0,102.64,192.0,3.79,79.0
+2020-02-12 11:00:00,3.06,272.0,147.83,209.0,3.72,76.1
+2020-02-12 12:00:00,3.51,134.0,2.43,133.0,3.59,70.5
+2020-02-12 13:00:00,3.6,122.0,2.81,121.0,3.66,67.8
+2020-02-12 14:00:00,3.13,52.0,0.0,52.0,3.72,65.1
+2020-02-12 15:00:00,2.83,12.0,0.0,12.0,2.9,67.6
+2020-02-12 16:00:00,1.8,0.0,-0.0,0.0,2.07,70.1
+2020-02-12 17:00:00,0.43,0.0,-0.0,0.0,2.07,72.75
+2020-02-12 18:00:00,-0.57,0.0,-0.0,0.0,2.28,75.55
+2020-02-12 19:00:00,-0.84,0.0,-0.0,0.0,2.69,85.0
+2020-02-12 20:00:00,-1.02,0.0,-0.0,0.0,2.48,85.0
+2020-02-12 21:00:00,-1.4,0.0,-0.0,0.0,2.41,88.35
+2020-02-12 22:00:00,-1.57,0.0,-0.0,0.0,2.48,84.95
+2020-02-12 23:00:00,-1.78,0.0,-0.0,0.0,2.41,88.3
+2020-02-13 00:00:00,-2.05,0.0,-0.0,0.0,2.34,88.3
+2020-02-13 01:00:00,-2.33,0.0,-0.0,0.0,2.21,84.85
+2020-02-13 02:00:00,-2.81,0.0,-0.0,0.0,2.0,88.25
+2020-02-13 03:00:00,-3.46,0.0,-0.0,0.0,1.93,88.25
+2020-02-13 04:00:00,-3.67,0.0,-0.0,0.0,1.86,84.8
+2020-02-13 05:00:00,-3.93,0.0,-0.0,0.0,1.86,88.2
+2020-02-13 06:00:00,-4.06,0.0,-0.0,0.0,1.86,84.7
+2020-02-13 07:00:00,-2.84,67.0,292.44,36.0,1.59,84.85
+2020-02-13 08:00:00,-0.71,206.0,596.88,65.0,1.52,85.0
+2020-02-13 09:00:00,1.36,325.0,727.6,79.0,1.93,67.3
+2020-02-13 10:00:00,2.26,405.0,788.27,86.0,1.45,62.35
+2020-02-13 11:00:00,2.93,385.0,523.83,159.0,1.1,53.4
+2020-02-13 12:00:00,3.53,197.0,33.61,183.0,0.83,49.4
+2020-02-13 13:00:00,3.52,253.0,227.15,171.0,0.41,47.45
+2020-02-13 14:00:00,3.32,207.0,368.56,108.0,0.34,49.25
+2020-02-13 15:00:00,2.9,112.0,487.39,41.0,0.9,53.4
+2020-02-13 16:00:00,1.8,0.0,0.0,0.0,1.52,62.25
+2020-02-13 17:00:00,0.23,0.0,-0.0,0.0,1.59,69.85
+2020-02-13 18:00:00,-1.42,0.0,-0.0,0.0,1.72,75.35
+2020-02-13 19:00:00,-2.18,0.0,-0.0,0.0,1.66,75.3
+2020-02-13 20:00:00,-2.51,0.0,-0.0,0.0,1.66,75.3
+2020-02-13 21:00:00,-2.7,0.0,-0.0,0.0,1.59,78.3
+2020-02-13 22:00:00,-2.67,0.0,-0.0,0.0,1.52,75.3
+2020-02-13 23:00:00,-2.38,0.0,-0.0,0.0,1.38,75.3
+2020-02-14 00:00:00,-1.92,0.0,-0.0,0.0,1.17,78.35
+2020-02-14 01:00:00,-1.54,0.0,-0.0,0.0,1.1,78.45
+2020-02-14 02:00:00,-1.71,0.0,-0.0,0.0,1.1,81.55
+2020-02-14 03:00:00,-1.84,0.0,-0.0,0.0,1.1,81.55
+2020-02-14 04:00:00,-2.25,0.0,-0.0,0.0,1.17,78.35
+2020-02-14 05:00:00,-2.59,0.0,-0.0,0.0,1.24,78.35
+2020-02-14 06:00:00,-2.94,0.0,-0.0,0.0,1.24,81.5
+2020-02-14 07:00:00,-2.16,74.0,333.69,37.0,0.97,88.3
+2020-02-14 08:00:00,-1.74,213.0,609.24,66.0,0.69,88.3
+2020-02-14 09:00:00,0.39,333.0,736.97,80.0,1.45,75.7
+2020-02-14 10:00:00,1.65,408.0,768.35,93.0,1.79,67.4
+2020-02-14 11:00:00,2.63,428.0,716.64,115.0,2.07,57.7
+2020-02-14 12:00:00,3.06,309.0,248.91,204.0,2.07,51.3
+2020-02-14 13:00:00,3.2,265.0,251.21,173.0,2.0,47.3
+2020-02-14 14:00:00,3.15,229.0,485.92,96.0,2.0,45.4
+2020-02-14 15:00:00,2.37,124.0,577.71,37.0,1.79,51.15
+2020-02-14 16:00:00,1.03,0.0,0.0,0.0,1.93,59.7
+2020-02-14 17:00:00,-0.46,0.0,-0.0,0.0,1.86,69.75
+2020-02-14 18:00:00,-2.08,0.0,-0.0,0.0,1.86,78.35
+2020-02-14 19:00:00,-3.17,0.0,-0.0,0.0,1.79,81.5
+2020-02-14 20:00:00,-3.24,0.0,-0.0,0.0,1.66,84.8
+2020-02-14 21:00:00,-3.52,0.0,-0.0,0.0,1.72,84.8
+2020-02-14 22:00:00,-4.08,0.0,-0.0,0.0,1.86,88.2
+2020-02-14 23:00:00,-4.42,0.0,-0.0,0.0,2.0,88.15
+2020-02-15 00:00:00,-4.63,0.0,-0.0,0.0,2.0,88.15
+2020-02-15 01:00:00,-4.89,0.0,-0.0,0.0,2.0,88.1
+2020-02-15 02:00:00,-4.94,0.0,-0.0,0.0,2.07,88.1
+2020-02-15 03:00:00,-4.92,0.0,-0.0,0.0,2.07,88.1
+2020-02-15 04:00:00,-4.82,0.0,-0.0,0.0,2.28,88.1
+2020-02-15 05:00:00,-4.52,0.0,-0.0,0.0,2.48,84.65
+2020-02-15 06:00:00,-4.02,0.0,-0.0,0.0,2.62,84.7
+2020-02-15 07:00:00,-3.21,43.0,25.9,40.0,2.55,88.25
+2020-02-15 08:00:00,-1.54,138.0,109.57,111.0,2.69,84.95
+2020-02-15 09:00:00,0.01,228.0,177.88,166.0,3.86,72.65
+2020-02-15 10:00:00,1.06,296.0,235.97,198.0,4.48,64.65
+2020-02-15 11:00:00,1.9,303.0,194.52,217.0,4.69,57.6
+2020-02-15 12:00:00,2.41,306.0,236.44,205.0,4.76,51.15
+2020-02-15 13:00:00,2.72,257.0,218.05,176.0,4.69,51.15
+2020-02-15 14:00:00,2.71,125.0,35.87,115.0,4.55,51.15
+2020-02-15 15:00:00,2.27,64.0,38.58,58.0,4.14,53.15
+2020-02-15 16:00:00,1.72,0.0,0.0,0.0,4.21,55.2
+2020-02-15 17:00:00,1.48,0.0,-0.0,0.0,4.21,55.2
+2020-02-15 18:00:00,1.41,0.0,-0.0,0.0,4.21,55.2
+2020-02-15 19:00:00,1.22,0.0,-0.0,0.0,4.21,70.05
+2020-02-15 20:00:00,1.29,0.0,-0.0,0.0,4.07,70.05
+2020-02-15 21:00:00,0.96,0.0,-0.0,0.0,3.59,70.05
+2020-02-15 22:00:00,0.96,0.0,-0.0,0.0,3.38,72.85
+2020-02-15 23:00:00,1.17,0.0,-0.0,0.0,2.97,78.8
+2020-02-16 00:00:00,1.06,0.0,-0.0,0.0,2.55,85.2
+2020-02-16 01:00:00,1.47,0.0,-0.0,0.0,2.21,92.05
+2020-02-16 02:00:00,1.76,0.0,-0.0,0.0,2.07,95.65
+2020-02-16 03:00:00,1.93,0.0,-0.0,0.0,2.48,95.65
+2020-02-16 04:00:00,1.88,0.0,-0.0,0.0,2.48,95.65
+2020-02-16 05:00:00,1.67,0.0,-0.0,0.0,2.14,99.4
+2020-02-16 06:00:00,1.4,0.0,-0.0,0.0,2.0,99.4
+2020-02-16 07:00:00,0.55,86.0,421.96,35.0,2.41,99.4
+2020-02-16 08:00:00,1.67,222.0,624.0,65.0,2.9,95.65
+2020-02-16 09:00:00,2.62,338.0,731.91,79.0,3.66,88.65
+2020-02-16 10:00:00,3.97,416.0,777.29,89.0,3.24,82.3
+2020-02-16 11:00:00,5.15,437.0,735.15,108.0,3.1,76.4
+2020-02-16 12:00:00,6.1,420.0,725.95,106.0,3.24,68.3
+2020-02-16 13:00:00,6.54,354.0,679.51,98.0,3.59,63.35
+2020-02-16 14:00:00,6.27,251.0,605.73,79.0,3.52,63.25
+2020-02-16 15:00:00,5.46,127.0,523.4,43.0,2.76,68.2
+2020-02-16 16:00:00,3.78,0.0,0.0,0.0,2.62,76.15
+2020-02-16 17:00:00,2.37,0.0,-0.0,0.0,2.62,82.15
+2020-02-16 18:00:00,1.42,0.0,-0.0,0.0,2.62,88.6
+2020-02-16 19:00:00,1.19,0.0,-0.0,0.0,2.55,92.05
+2020-02-16 20:00:00,0.57,0.0,-0.0,0.0,2.41,92.0
+2020-02-16 21:00:00,0.14,0.0,-0.0,0.0,2.21,92.0
+2020-02-16 22:00:00,-0.67,0.0,-0.0,0.0,2.07,95.6
+2020-02-16 23:00:00,-1.47,0.0,-0.0,0.0,2.0,91.9
+2020-02-17 00:00:00,-2.21,0.0,-0.0,0.0,2.0,91.85
+2020-02-17 01:00:00,-2.42,0.0,-0.0,0.0,1.79,88.3
+2020-02-17 02:00:00,-2.36,0.0,-0.0,0.0,1.59,88.3
+2020-02-17 03:00:00,-2.53,0.0,-0.0,0.0,1.52,88.3
+2020-02-17 04:00:00,-2.47,0.0,-0.0,0.0,1.38,91.85
+2020-02-17 05:00:00,-2.55,0.0,-0.0,0.0,1.31,91.85
+2020-02-17 06:00:00,-2.18,0.0,-0.0,0.0,1.17,91.85
+2020-02-17 07:00:00,-0.7,44.0,23.82,41.0,0.9,91.95
+2020-02-17 08:00:00,0.24,151.0,136.26,116.0,0.69,95.6
+2020-02-17 09:00:00,2.33,224.0,144.75,172.0,0.9,82.05
+2020-02-17 10:00:00,3.1,285.0,180.7,208.0,1.45,76.1
+2020-02-17 11:00:00,3.65,290.0,145.71,224.0,1.79,65.2
+2020-02-17 12:00:00,3.99,276.0,139.29,215.0,1.86,62.8
+2020-02-17 13:00:00,3.93,215.0,89.0,181.0,2.14,60.4
+2020-02-17 14:00:00,3.61,165.0,110.69,133.0,2.21,62.7
+2020-02-17 15:00:00,3.1,76.0,60.44,66.0,1.86,70.4
+2020-02-17 16:00:00,2.16,0.0,0.0,0.0,1.93,75.95
+2020-02-17 17:00:00,1.39,0.0,-0.0,0.0,1.86,82.0
+2020-02-17 18:00:00,0.85,0.0,-0.0,0.0,1.86,88.55
+2020-02-17 19:00:00,0.03,0.0,-0.0,0.0,1.59,92.0
+2020-02-17 20:00:00,-0.76,0.0,-0.0,0.0,1.45,95.6
+2020-02-17 21:00:00,-0.7,0.0,-0.0,0.0,1.24,99.4
+2020-02-17 22:00:00,-0.61,0.0,-0.0,0.0,1.17,95.6
+2020-02-17 23:00:00,-0.45,0.0,-0.0,0.0,1.1,99.4
+2020-02-18 00:00:00,-0.29,0.0,-0.0,0.0,1.03,99.4
+2020-02-18 01:00:00,-0.23,0.0,-0.0,0.0,1.03,100.0
+2020-02-18 02:00:00,-0.04,0.0,-0.0,0.0,1.17,99.4
+2020-02-18 03:00:00,-0.01,0.0,-0.0,0.0,1.17,99.4
+2020-02-18 04:00:00,-0.21,0.0,-0.0,0.0,1.03,100.0
+2020-02-18 05:00:00,-0.62,0.0,-0.0,0.0,0.9,99.4
+2020-02-18 06:00:00,-0.32,0.0,-0.0,0.0,0.69,95.6
+2020-02-18 07:00:00,-0.42,57.0,53.38,50.0,0.83,95.6
+2020-02-18 08:00:00,0.41,139.0,83.91,117.0,0.97,85.15
+2020-02-18 09:00:00,1.46,164.0,27.42,154.0,1.38,75.85
+2020-02-18 10:00:00,2.01,85.0,0.0,85.0,1.38,67.5
+2020-02-18 11:00:00,2.41,82.0,0.0,82.0,1.1,65.0
+2020-02-18 12:00:00,2.52,89.0,0.0,89.0,0.9,65.0
+2020-02-18 13:00:00,2.54,94.0,0.0,94.0,0.76,65.0
+2020-02-18 14:00:00,2.62,69.0,0.0,69.0,0.62,65.0
+2020-02-18 15:00:00,2.56,68.0,29.34,63.0,0.62,62.5
+2020-02-18 16:00:00,2.07,0.0,0.0,0.0,1.1,67.5
+2020-02-18 17:00:00,0.8,0.0,-0.0,0.0,1.38,78.75
+2020-02-18 18:00:00,-0.71,0.0,-0.0,0.0,1.52,85.0
+2020-02-18 19:00:00,-1.22,0.0,-0.0,0.0,1.66,88.35
+2020-02-18 20:00:00,-1.48,0.0,-0.0,0.0,1.72,84.95
+2020-02-18 21:00:00,-1.95,0.0,-0.0,0.0,1.72,88.3
+2020-02-18 22:00:00,-2.41,0.0,-0.0,0.0,1.72,84.85
+2020-02-18 23:00:00,-2.64,0.0,-0.0,0.0,1.79,84.85
+2020-02-19 00:00:00,-2.79,0.0,-0.0,0.0,1.93,84.85
+2020-02-19 01:00:00,-2.9,0.0,-0.0,0.0,2.0,84.85
+2020-02-19 02:00:00,-3.1,0.0,-0.0,0.0,1.93,81.5
+2020-02-19 03:00:00,-3.33,0.0,-0.0,0.0,1.86,84.8
+2020-02-19 04:00:00,-3.47,0.0,-0.0,0.0,1.86,84.8
+2020-02-19 05:00:00,-3.55,0.0,-0.0,0.0,1.86,84.8
+2020-02-19 06:00:00,-3.5,0.0,-0.0,0.0,1.86,84.8
+2020-02-19 07:00:00,-2.62,63.0,73.33,53.0,1.79,81.55
+2020-02-19 08:00:00,-0.79,229.0,530.74,87.0,1.93,78.5
+2020-02-19 09:00:00,0.49,317.0,478.21,140.0,2.21,67.2
+2020-02-19 10:00:00,1.25,353.0,363.75,194.0,2.21,59.7
+2020-02-19 11:00:00,1.8,435.0,607.84,153.0,1.93,57.45
+2020-02-19 12:00:00,2.35,425.0,639.51,138.0,1.66,55.3
+2020-02-19 13:00:00,2.7,386.0,751.26,91.0,1.59,57.7
+2020-02-19 14:00:00,2.42,235.0,377.38,122.0,1.79,57.7
+2020-02-19 15:00:00,2.04,143.0,541.55,48.0,1.66,59.95
+2020-02-19 16:00:00,0.9,2.0,0.0,2.0,1.72,64.65
+2020-02-19 17:00:00,-0.25,0.0,-0.0,0.0,1.72,72.6
+2020-02-19 18:00:00,-1.14,0.0,-0.0,0.0,1.52,75.45
+2020-02-19 19:00:00,-1.72,0.0,-0.0,0.0,1.38,81.55
+2020-02-19 20:00:00,-2.1,0.0,-0.0,0.0,1.38,81.55
+2020-02-19 21:00:00,-2.25,0.0,-0.0,0.0,1.38,81.55
+2020-02-19 22:00:00,-2.5,0.0,-0.0,0.0,1.52,81.55
+2020-02-19 23:00:00,-2.74,0.0,-0.0,0.0,1.66,84.85
+2020-02-20 00:00:00,-3.08,0.0,-0.0,0.0,1.86,84.85
+2020-02-20 01:00:00,-3.06,0.0,-0.0,0.0,1.79,84.85
+2020-02-20 02:00:00,-3.08,0.0,-0.0,0.0,1.72,84.85
+2020-02-20 03:00:00,-3.19,0.0,-0.0,0.0,1.72,88.25
+2020-02-20 04:00:00,-3.35,0.0,-0.0,0.0,1.72,88.25
+2020-02-20 05:00:00,-3.56,0.0,-0.0,0.0,1.72,84.8
+2020-02-20 06:00:00,-3.82,0.0,-0.0,0.0,1.72,88.2
+2020-02-20 07:00:00,-3.56,77.0,141.16,57.0,1.45,88.25
+2020-02-20 08:00:00,-1.26,217.0,413.94,104.0,1.52,78.45
+2020-02-20 09:00:00,0.08,317.0,455.21,146.0,1.72,69.85
+2020-02-20 10:00:00,1.33,426.0,684.49,123.0,1.93,62.15
+2020-02-20 11:00:00,2.42,462.0,724.21,122.0,2.07,55.45
+2020-02-20 12:00:00,3.12,451.0,752.9,109.0,2.0,53.4
+2020-02-20 13:00:00,3.35,354.0,540.18,139.0,2.14,53.4
+2020-02-20 14:00:00,3.03,187.0,144.44,143.0,2.28,57.8
+2020-02-20 15:00:00,2.37,132.0,376.9,64.0,2.41,62.5
+2020-02-20 16:00:00,0.9,3.0,0.0,3.0,2.55,70.05
+2020-02-20 17:00:00,-0.6,0.0,-0.0,0.0,2.48,78.6
+2020-02-20 18:00:00,-1.48,0.0,-0.0,0.0,2.48,84.95
+2020-02-20 19:00:00,-1.78,0.0,-0.0,0.0,2.41,84.85
+2020-02-20 20:00:00,-2.1,0.0,-0.0,0.0,2.28,81.55
+2020-02-20 21:00:00,-2.53,0.0,-0.0,0.0,2.0,81.55
+2020-02-20 22:00:00,-3.3,0.0,-0.0,0.0,1.86,84.8
+2020-02-20 23:00:00,-4.07,0.0,-0.0,0.0,1.72,84.7
+2020-02-21 00:00:00,-4.63,0.0,-0.0,0.0,1.86,84.65
+2020-02-21 01:00:00,-5.0,0.0,-0.0,0.0,2.0,88.1
+2020-02-21 02:00:00,-5.12,0.0,-0.0,0.0,2.07,84.6
+2020-02-21 03:00:00,-4.97,0.0,-0.0,0.0,2.21,84.6
+2020-02-21 04:00:00,-4.88,0.0,-0.0,0.0,2.21,84.6
+2020-02-21 05:00:00,-4.89,0.0,-0.0,0.0,2.07,84.6
+2020-02-21 06:00:00,-4.99,0.0,-0.0,0.0,1.86,84.6
+2020-02-21 07:00:00,-4.16,81.0,142.81,60.0,1.79,84.7
+2020-02-21 08:00:00,-3.34,143.0,68.23,124.0,2.76,81.45
+2020-02-21 09:00:00,-2.26,298.0,341.02,168.0,3.17,75.3
+2020-02-21 10:00:00,-1.2,459.0,832.12,86.0,3.31,72.4
+2020-02-21 11:00:00,-0.29,502.0,894.67,77.0,3.45,64.35
+2020-02-21 12:00:00,0.69,488.0,909.24,70.0,3.79,57.2
+2020-02-21 13:00:00,0.99,407.0,813.15,79.0,3.72,52.85
+2020-02-21 14:00:00,1.23,147.0,41.96,134.0,3.93,52.85
+2020-02-21 15:00:00,0.83,137.0,377.51,67.0,3.72,54.95
+2020-02-21 16:00:00,-0.13,5.0,0.0,5.0,2.97,59.45
+2020-02-21 17:00:00,-0.84,0.0,-0.0,0.0,2.62,66.9
+2020-02-21 18:00:00,-1.5,0.0,-0.0,0.0,2.34,72.4
+2020-02-21 19:00:00,-1.44,0.0,-0.0,0.0,2.76,72.4
+2020-02-21 20:00:00,-1.77,0.0,-0.0,0.0,2.55,78.35
+2020-02-21 21:00:00,-2.44,0.0,-0.0,0.0,2.41,78.35
+2020-02-21 22:00:00,-3.01,0.0,-0.0,0.0,2.34,81.5
+2020-02-21 23:00:00,-3.55,0.0,-0.0,0.0,2.28,81.45
+2020-02-22 00:00:00,-4.01,0.0,-0.0,0.0,2.14,84.7
+2020-02-22 01:00:00,-4.3,0.0,-0.0,0.0,2.07,84.65
+2020-02-22 02:00:00,-4.73,0.0,-0.0,0.0,2.07,84.6
+2020-02-22 03:00:00,-4.82,0.0,-0.0,0.0,2.21,84.6
+2020-02-22 04:00:00,-4.76,0.0,-0.0,0.0,2.34,84.6
+2020-02-22 05:00:00,-4.55,0.0,-0.0,0.0,2.41,81.3
+2020-02-22 06:00:00,-4.37,0.0,0.0,0.0,2.41,81.3
+2020-02-22 07:00:00,-4.04,121.0,504.99,44.0,2.48,78.15
+2020-02-22 08:00:00,-2.94,275.0,764.03,58.0,3.17,69.35
+2020-02-22 09:00:00,-1.63,400.0,863.45,66.0,4.28,61.55
+2020-02-22 10:00:00,-0.73,478.0,887.91,75.0,4.21,59.2
+2020-02-22 11:00:00,0.09,509.0,890.52,81.0,4.28,52.6
+2020-02-22 12:00:00,0.26,482.0,846.91,88.0,4.41,50.5
+2020-02-22 13:00:00,0.41,350.0,455.06,164.0,4.48,46.6
+2020-02-22 14:00:00,0.39,275.0,536.49,106.0,4.41,44.75
+2020-02-22 15:00:00,0.09,132.0,288.81,77.0,4.21,46.5
+2020-02-22 16:00:00,-0.63,6.0,0.0,6.0,3.45,50.35
+2020-02-22 17:00:00,-1.57,0.0,-0.0,0.0,3.1,54.4
+2020-02-22 18:00:00,-2.2,0.0,-0.0,0.0,2.97,58.95
+2020-02-22 19:00:00,-2.48,0.0,-0.0,0.0,3.1,58.95
+2020-02-22 20:00:00,-2.97,0.0,-0.0,0.0,2.97,61.35
+2020-02-22 21:00:00,-3.19,0.0,-0.0,0.0,2.83,63.8
+2020-02-22 22:00:00,-3.4,0.0,-0.0,0.0,2.83,63.8
+2020-02-22 23:00:00,-3.44,0.0,-0.0,0.0,2.76,63.8
+2020-02-23 00:00:00,-3.71,0.0,-0.0,0.0,2.76,66.35
+2020-02-23 01:00:00,-4.66,0.0,-0.0,0.0,2.76,66.25
+2020-02-23 02:00:00,-5.03,0.0,-0.0,0.0,2.9,68.95
+2020-02-23 03:00:00,-5.28,0.0,-0.0,0.0,3.17,68.85
+2020-02-23 04:00:00,-5.52,0.0,-0.0,0.0,3.17,66.05
+2020-02-23 05:00:00,-5.66,0.0,-0.0,0.0,3.31,63.35
+2020-02-23 06:00:00,-5.83,0.0,0.0,0.0,3.38,63.25
+2020-02-23 07:00:00,-5.51,126.0,512.76,45.0,3.59,68.85
+2020-02-23 08:00:00,-5.34,280.0,752.73,62.0,3.72,66.05
+2020-02-23 09:00:00,-4.82,392.0,769.49,90.0,3.59,60.85
+2020-02-23 10:00:00,-4.19,493.0,916.16,72.0,3.45,58.5
+2020-02-23 11:00:00,-3.51,529.0,944.01,70.0,3.45,54.0
+2020-02-23 12:00:00,-3.04,502.0,898.61,79.0,3.52,51.95
+2020-02-23 13:00:00,-3.03,425.0,828.29,82.0,3.52,51.95
+2020-02-23 14:00:00,-3.07,312.0,758.87,69.0,3.52,51.95
+2020-02-23 15:00:00,-3.28,172.0,634.45,48.0,3.52,54.0
+2020-02-23 16:00:00,-3.96,0.0,0.0,0.0,3.24,56.2
+2020-02-23 17:00:00,-4.88,0.0,-0.0,0.0,2.9,60.85
+2020-02-23 18:00:00,-5.46,0.0,-0.0,0.0,2.83,60.75
+2020-02-23 19:00:00,-5.68,0.0,-0.0,0.0,2.83,60.75
+2020-02-23 20:00:00,-5.95,0.0,-0.0,0.0,2.62,63.25
+2020-02-23 21:00:00,-6.16,0.0,-0.0,0.0,2.21,65.95
+2020-02-23 22:00:00,-6.4,0.0,-0.0,0.0,2.07,68.65
+2020-02-23 23:00:00,-6.59,0.0,-0.0,0.0,2.07,68.65
+2020-02-24 00:00:00,-6.83,0.0,-0.0,0.0,2.28,71.5
+2020-02-24 01:00:00,-6.65,0.0,-0.0,0.0,2.28,71.55
+2020-02-24 02:00:00,-6.82,0.0,-0.0,0.0,2.14,74.55
+2020-02-24 03:00:00,-6.96,0.0,-0.0,0.0,2.14,71.5
+2020-02-24 04:00:00,-6.88,0.0,-0.0,0.0,2.28,71.5
+2020-02-24 05:00:00,-6.69,0.0,-0.0,0.0,2.21,65.8
+2020-02-24 06:00:00,-6.05,0.0,0.0,0.0,2.21,65.95
+2020-02-24 07:00:00,-6.1,67.0,30.58,62.0,1.59,74.7
+2020-02-24 08:00:00,-4.44,230.0,365.79,122.0,2.76,78.05
+2020-02-24 09:00:00,-3.11,382.0,690.69,107.0,3.86,66.6
+2020-02-24 10:00:00,-2.06,444.0,647.02,143.0,4.28,56.6
+2020-02-24 11:00:00,-1.55,463.0,607.92,164.0,4.55,44.15
+2020-02-24 12:00:00,-1.25,414.0,464.04,193.0,4.69,40.55
+2020-02-24 13:00:00,-1.31,278.0,171.64,206.0,4.83,40.55
+2020-02-24 14:00:00,-1.84,189.0,110.63,153.0,4.83,42.2
+2020-02-24 15:00:00,-2.44,168.0,558.72,56.0,4.83,42.2
+2020-02-24 16:00:00,-3.28,13.0,18.82,12.0,4.55,45.65
+2020-02-24 17:00:00,-3.97,0.0,-0.0,0.0,4.21,47.45
+2020-02-24 18:00:00,-4.24,0.0,-0.0,0.0,4.21,49.4
+2020-02-24 19:00:00,-5.03,0.0,-0.0,0.0,3.66,49.25
+2020-02-24 20:00:00,-5.64,0.0,-0.0,0.0,3.31,51.25
+2020-02-24 21:00:00,-6.19,0.0,-0.0,0.0,3.03,55.7
+2020-02-24 22:00:00,-6.66,0.0,-0.0,0.0,2.76,58.0
+2020-02-24 23:00:00,-7.1,0.0,-0.0,0.0,2.55,60.4
+2020-02-25 00:00:00,-7.46,0.0,-0.0,0.0,2.55,62.9
+2020-02-25 01:00:00,-7.85,0.0,-0.0,0.0,2.55,65.5
+2020-02-25 02:00:00,-8.14,0.0,-0.0,0.0,2.55,62.75
+2020-02-25 03:00:00,-8.5,0.0,-0.0,0.0,2.48,62.65
+2020-02-25 04:00:00,-8.87,0.0,-0.0,0.0,2.48,62.5
+2020-02-25 05:00:00,-9.32,0.0,-0.0,0.0,2.34,65.15
+2020-02-25 06:00:00,-9.67,0.0,0.0,0.0,2.34,62.4
+2020-02-25 07:00:00,-9.77,148.0,644.55,39.0,2.76,65.05
+2020-02-25 08:00:00,-9.09,302.0,820.78,55.0,3.17,57.35
+2020-02-25 09:00:00,-8.1,431.0,921.08,59.0,3.24,50.55
+2020-02-25 10:00:00,-6.95,512.0,940.73,69.0,3.24,46.6
+2020-02-25 11:00:00,-5.87,548.0,968.87,66.0,3.38,41.15
+2020-02-25 12:00:00,-5.05,512.0,884.22,86.0,3.52,38.0
+2020-02-25 13:00:00,-4.52,444.0,861.45,78.0,3.66,34.95
+2020-02-25 14:00:00,-4.35,329.0,792.45,67.0,3.72,33.45
+2020-02-25 15:00:00,-4.58,187.0,686.23,46.0,3.66,34.95
+2020-02-25 16:00:00,-5.18,18.0,34.52,16.0,3.59,36.35
+2020-02-25 17:00:00,-5.87,0.0,-0.0,0.0,3.24,41.15
+2020-02-25 18:00:00,-6.46,0.0,-0.0,0.0,2.97,44.75
+2020-02-25 19:00:00,-7.04,0.0,-0.0,0.0,2.83,48.7
+2020-02-25 20:00:00,-7.49,0.0,-0.0,0.0,2.41,52.95
+2020-02-25 21:00:00,-7.88,0.0,-0.0,0.0,2.07,55.15
+2020-02-25 22:00:00,-8.28,0.0,-0.0,0.0,1.79,57.5
+2020-02-25 23:00:00,-8.61,0.0,-0.0,0.0,1.66,57.5
+2020-02-26 00:00:00,-8.87,0.0,-0.0,0.0,1.52,62.5
+2020-02-26 01:00:00,-9.13,0.0,-0.0,0.0,1.38,65.25
+2020-02-26 02:00:00,-9.44,0.0,-0.0,0.0,1.38,68.0
+2020-02-26 03:00:00,-9.37,0.0,-0.0,0.0,1.59,71.0
+2020-02-26 04:00:00,-9.16,0.0,-0.0,0.0,2.0,71.1
+2020-02-26 05:00:00,-9.24,0.0,-0.0,0.0,2.34,74.1
+2020-02-26 06:00:00,-9.58,0.0,0.0,0.0,2.76,71.0
+2020-02-26 07:00:00,-9.59,152.0,629.43,42.0,3.93,59.75
+2020-02-26 08:00:00,-9.27,297.0,750.02,67.0,3.79,59.75
+2020-02-26 09:00:00,-8.56,424.0,849.56,76.0,3.59,55.05
+2020-02-26 10:00:00,-7.79,421.0,474.15,195.0,3.45,50.55
+2020-02-26 11:00:00,-6.99,350.0,184.84,257.0,3.45,48.7
+2020-02-26 12:00:00,-6.37,283.0,84.13,242.0,3.79,44.75
+2020-02-26 13:00:00,-6.11,219.0,46.48,199.0,4.0,43.0
+2020-02-26 14:00:00,-6.2,161.0,41.69,147.0,4.0,43.0
+2020-02-26 15:00:00,-6.41,111.0,90.27,92.0,3.86,44.75
+2020-02-26 16:00:00,-6.78,16.0,15.93,15.0,3.72,44.65
+2020-02-26 17:00:00,-7.25,0.0,-0.0,0.0,3.52,46.5
+2020-02-26 18:00:00,-7.67,0.0,-0.0,0.0,3.31,46.5
+2020-02-26 19:00:00,-8.35,0.0,-0.0,0.0,3.31,50.45
+2020-02-26 20:00:00,-8.93,0.0,-0.0,0.0,3.1,52.55
+2020-02-26 21:00:00,-9.44,0.0,-0.0,0.0,2.97,54.75
+2020-02-26 22:00:00,-9.86,0.0,-0.0,0.0,2.76,54.65
+2020-02-26 23:00:00,-10.16,0.0,-0.0,0.0,2.76,54.65
+2020-02-27 00:00:00,-10.49,0.0,-0.0,0.0,2.55,54.5
+2020-02-27 01:00:00,-10.93,0.0,-0.0,0.0,2.41,54.35
+2020-02-27 02:00:00,-11.11,0.0,-0.0,0.0,2.34,54.35
+2020-02-27 03:00:00,-11.35,0.0,-0.0,0.0,2.41,56.7
+2020-02-27 04:00:00,-11.63,0.0,-0.0,0.0,2.41,54.25
+2020-02-27 05:00:00,-11.84,0.0,-0.0,0.0,2.48,56.55
+2020-02-27 06:00:00,-12.05,0.0,0.0,0.0,2.41,56.55
+2020-02-27 07:00:00,-12.11,155.0,609.55,45.0,2.97,67.5
+2020-02-27 08:00:00,-11.15,309.0,787.39,63.0,3.1,62.05
+2020-02-27 09:00:00,-9.76,441.0,902.73,66.0,3.17,54.65
+2020-02-27 10:00:00,-8.09,530.0,970.17,62.0,3.52,44.35
+2020-02-27 11:00:00,-6.77,566.0,994.49,60.0,3.72,40.85
+2020-02-27 12:00:00,-5.93,536.0,937.39,74.0,3.86,37.7
+2020-02-27 13:00:00,-4.92,461.0,890.66,73.0,5.17,33.3
+2020-02-27 14:00:00,-4.84,343.0,809.32,67.0,5.03,31.85
+2020-02-27 15:00:00,-5.1,188.0,593.99,60.0,4.62,31.85
+2020-02-27 16:00:00,-5.7,23.0,29.6,21.0,4.21,34.65
+2020-02-27 17:00:00,-6.65,0.0,-0.0,0.0,3.66,37.55
+2020-02-27 18:00:00,-7.41,0.0,-0.0,0.0,3.38,42.55
+2020-02-27 19:00:00,-8.48,0.0,-0.0,0.0,3.52,50.45
+2020-02-27 20:00:00,-8.96,0.0,-0.0,0.0,3.45,52.55
+2020-02-27 21:00:00,-9.55,0.0,-0.0,0.0,3.1,54.75
+2020-02-27 22:00:00,-10.03,0.0,-0.0,0.0,2.83,54.65
+2020-02-27 23:00:00,-10.42,0.0,-0.0,0.0,2.55,54.5
+2020-02-28 00:00:00,-10.73,0.0,-0.0,0.0,2.48,54.5
+2020-02-28 01:00:00,-11.03,0.0,-0.0,0.0,2.48,54.35
+2020-02-28 02:00:00,-11.3,0.0,-0.0,0.0,2.48,56.7
+2020-02-28 03:00:00,-11.53,0.0,-0.0,0.0,2.69,56.7
+2020-02-28 04:00:00,-11.74,0.0,-0.0,0.0,2.76,56.7
+2020-02-28 05:00:00,-11.94,0.0,-0.0,0.0,2.83,56.55
+2020-02-28 06:00:00,-12.14,5.0,0.0,5.0,2.9,56.55
+2020-02-28 07:00:00,-12.22,162.0,633.71,44.0,3.52,67.5
+2020-02-28 08:00:00,-11.27,298.0,672.48,84.0,3.72,61.95
+2020-02-28 09:00:00,-9.96,429.0,814.31,86.0,3.79,52.3
+2020-02-28 10:00:00,-8.74,488.0,735.42,129.0,3.72,48.1
+2020-02-28 11:00:00,-7.62,551.0,905.77,85.0,3.66,42.55
+2020-02-28 12:00:00,-6.79,536.0,920.95,77.0,3.66,42.7
+2020-02-28 13:00:00,-6.19,467.0,897.94,71.0,3.72,39.4
+2020-02-28 14:00:00,-5.89,349.0,817.39,66.0,3.86,41.15
+2020-02-28 15:00:00,-6.08,202.0,698.43,48.0,4.07,41.15
+2020-02-28 16:00:00,-9.4,25.0,41.44,22.0,3.69,41.97
+2020-02-28 17:00:00,-8.84,0.0,-0.0,0.0,3.63,46.49
+2020-02-28 18:00:00,-8.27,0.0,-0.0,0.0,3.57,51.0
+2020-02-28 19:00:00,-7.7,0.0,-0.0,0.0,3.51,55.52
+2020-02-28 20:00:00,-7.13,0.0,-0.0,0.0,3.45,60.03
+2020-02-28 21:00:00,-6.57,0.0,-0.0,0.0,3.39,64.55
+2020-02-28 22:00:00,-6.0,0.0,-0.0,0.0,3.32,69.06
+2020-02-28 23:00:00,-5.43,0.0,-0.0,0.0,3.26,73.58
+2020-03-01 00:00:00,-4.86,0.0,-0.0,0.0,3.2,78.09
+2020-03-01 01:00:00,-4.3,0.0,-0.0,0.0,3.14,82.61
+2020-03-01 02:00:00,-3.73,0.0,-0.0,0.0,3.08,87.12
+2020-03-01 03:00:00,-3.16,0.0,-0.0,0.0,3.02,91.64
+2020-03-01 04:00:00,-2.59,0.0,-0.0,0.0,2.96,96.15
+2020-03-01 05:00:00,-2.03,0.0,-0.0,0.0,2.89,100.0
+2020-03-01 06:00:00,-1.46,2.0,0.0,2.0,2.83,100.0
+2020-03-01 07:00:00,-0.89,38.0,0.0,38.0,2.77,100.0
+2020-03-01 08:00:00,-2.05,55.0,0.0,55.0,2.83,95.55
+2020-03-01 09:00:00,-1.41,117.0,0.0,117.0,2.76,88.35
+2020-03-01 10:00:00,-0.87,66.0,0.0,66.0,2.9,85.05
+2020-03-01 11:00:00,-0.64,58.0,0.0,58.0,3.52,85.05
+2020-03-01 12:00:00,-0.64,502.0,751.74,119.0,3.66,88.45
+2020-03-01 13:00:00,-0.65,61.0,0.0,61.0,3.38,88.45
+2020-03-01 14:00:00,-0.57,60.0,0.0,60.0,3.24,88.45
+2020-03-01 15:00:00,-0.48,54.0,0.0,54.0,3.03,88.45
+2020-03-01 16:00:00,-0.54,34.0,97.54,26.0,2.48,88.45
+2020-03-01 17:00:00,-0.83,0.0,-0.0,0.0,1.93,88.45
+2020-03-01 18:00:00,-1.16,0.0,-0.0,0.0,1.79,91.95
+2020-03-01 19:00:00,-1.86,0.0,-0.0,0.0,2.07,88.35
+2020-03-01 20:00:00,-2.66,0.0,-0.0,0.0,2.41,88.25
+2020-03-01 21:00:00,-3.37,0.0,-0.0,0.0,2.69,81.45
+2020-03-01 22:00:00,-3.99,0.0,-0.0,0.0,2.83,84.65
+2020-03-01 23:00:00,-4.24,0.0,-0.0,0.0,2.9,81.3
+2020-03-02 00:00:00,-3.95,0.0,-0.0,0.0,2.9,84.65
+2020-03-02 01:00:00,-3.04,0.0,-0.0,0.0,2.83,84.8
+2020-03-02 02:00:00,-1.83,0.0,-0.0,0.0,2.9,84.95
+2020-03-02 03:00:00,-0.42,0.0,-0.0,0.0,2.97,88.45
+2020-03-02 04:00:00,0.74,0.0,-0.0,0.0,2.97,85.2
+2020-03-02 05:00:00,1.56,0.0,-0.0,0.0,3.1,85.25
+2020-03-02 06:00:00,1.97,3.0,0.0,3.0,3.17,82.05
+2020-03-02 07:00:00,2.26,59.0,4.91,58.0,3.31,82.15
+2020-03-02 08:00:00,3.03,71.0,0.0,71.0,3.38,82.2
+2020-03-02 09:00:00,3.68,105.0,0.0,105.0,3.52,82.25
+2020-03-02 10:00:00,4.27,96.0,0.0,96.0,3.72,82.3
+2020-03-02 11:00:00,4.95,245.0,28.22,230.0,3.52,82.35
+2020-03-02 12:00:00,6.04,122.0,0.0,122.0,3.66,79.4
+2020-03-02 13:00:00,6.51,103.0,0.0,103.0,3.79,79.5
+2020-03-02 14:00:00,6.53,64.0,0.0,64.0,3.59,79.5
+2020-03-02 15:00:00,5.94,36.0,0.0,36.0,3.38,82.5
+2020-03-02 16:00:00,5.08,14.0,0.0,14.0,3.03,85.55
+2020-03-02 17:00:00,4.22,0.0,-0.0,0.0,2.76,88.8
+2020-03-02 18:00:00,3.63,0.0,-0.0,0.0,2.28,92.15
+2020-03-02 19:00:00,2.77,0.0,-0.0,0.0,1.86,92.15
+2020-03-02 20:00:00,2.67,0.0,-0.0,0.0,2.07,88.7
+2020-03-02 21:00:00,2.69,0.0,-0.0,0.0,2.41,88.7
+2020-03-02 22:00:00,2.29,0.0,-0.0,0.0,2.14,92.15
+2020-03-02 23:00:00,1.7,0.0,-0.0,0.0,1.72,92.1
+2020-03-03 00:00:00,1.26,0.0,-0.0,0.0,1.66,92.05
+2020-03-03 01:00:00,0.83,0.0,-0.0,0.0,1.52,92.05
+2020-03-03 02:00:00,0.15,0.0,-0.0,0.0,0.0,92.0
+2020-03-03 03:00:00,0.01,0.0,-0.0,0.0,0.0,92.0
+2020-03-03 04:00:00,-0.14,0.0,-0.0,0.0,1.45,92.0
+2020-03-03 05:00:00,-0.46,0.0,-0.0,0.0,1.52,95.6
+2020-03-03 06:00:00,-0.62,21.0,87.38,16.0,1.52,91.95
+2020-03-03 07:00:00,0.92,90.0,38.17,82.0,0.97,92.05
+2020-03-03 08:00:00,2.04,60.0,0.0,60.0,1.1,88.65
+2020-03-03 09:00:00,2.77,187.0,17.99,179.0,2.76,82.2
+2020-03-03 10:00:00,3.12,263.0,52.8,236.0,2.14,79.1
+2020-03-03 11:00:00,3.38,324.0,109.82,265.0,1.79,79.1
+2020-03-03 12:00:00,3.68,179.0,1.92,178.0,1.66,73.3
+2020-03-03 13:00:00,3.68,212.0,30.27,198.0,1.45,73.3
+2020-03-03 14:00:00,3.87,193.0,73.58,166.0,1.17,70.5
+2020-03-03 15:00:00,4.57,45.0,0.0,45.0,1.03,67.9
+2020-03-03 16:00:00,3.58,24.0,10.92,23.0,1.17,73.2
+2020-03-03 17:00:00,2.54,0.0,-0.0,0.0,1.52,76.0
+2020-03-03 18:00:00,3.07,0.0,-0.0,0.0,1.24,73.2
+2020-03-03 19:00:00,3.52,0.0,-0.0,0.0,0.76,73.2
+2020-03-03 20:00:00,2.99,0.0,-0.0,0.0,1.1,73.2
+2020-03-03 21:00:00,1.35,0.0,-0.0,0.0,1.38,78.9
+2020-03-03 22:00:00,-0.26,0.0,-0.0,0.0,1.59,81.8
+2020-03-03 23:00:00,-1.19,0.0,-0.0,0.0,1.66,85.0
+2020-03-04 00:00:00,-1.63,0.0,-0.0,0.0,1.66,88.35
+2020-03-04 01:00:00,-1.82,0.0,-0.0,0.0,1.66,84.95
+2020-03-04 02:00:00,-2.21,0.0,-0.0,0.0,1.79,84.85
+2020-03-04 03:00:00,-1.97,0.0,-0.0,0.0,1.79,81.55
+2020-03-04 04:00:00,-1.36,0.0,-0.0,0.0,1.66,75.45
+2020-03-04 05:00:00,-1.08,0.0,-0.0,0.0,1.59,78.5
+2020-03-04 06:00:00,-1.45,29.0,158.47,19.0,1.59,78.45
+2020-03-04 07:00:00,0.6,179.0,533.55,64.0,1.03,81.9
+2020-03-04 08:00:00,2.86,321.0,652.86,94.0,0.76,73.2
+2020-03-04 09:00:00,4.05,438.0,714.64,116.0,1.1,70.5
+2020-03-04 10:00:00,4.58,508.0,709.64,141.0,1.93,70.6
+2020-03-04 11:00:00,5.18,512.0,611.51,180.0,2.76,60.65
+2020-03-04 12:00:00,5.87,397.0,275.62,252.0,2.9,56.2
+2020-03-04 13:00:00,6.09,445.0,656.25,138.0,3.17,56.2
+2020-03-04 14:00:00,7.37,250.0,201.57,175.0,3.45,48.4
+2020-03-04 15:00:00,7.15,173.0,289.33,102.0,3.38,50.2
+2020-03-04 16:00:00,5.97,44.0,103.74,34.0,2.83,54.05
+2020-03-04 17:00:00,4.55,0.0,-0.0,0.0,2.9,58.05
+2020-03-04 18:00:00,3.73,0.0,-0.0,0.0,3.24,60.3
+2020-03-04 19:00:00,3.47,0.0,-0.0,0.0,3.86,65.1
+2020-03-04 20:00:00,3.53,0.0,-0.0,0.0,4.0,67.7
+2020-03-04 21:00:00,3.51,0.0,-0.0,0.0,4.07,70.4
+2020-03-04 22:00:00,3.35,0.0,-0.0,0.0,4.0,70.4
+2020-03-04 23:00:00,3.33,0.0,-0.0,0.0,4.07,73.2
+2020-03-05 00:00:00,2.97,0.0,-0.0,0.0,3.86,73.2
+2020-03-05 01:00:00,2.06,0.0,-0.0,0.0,3.66,78.95
+2020-03-05 02:00:00,1.72,0.0,-0.0,0.0,3.59,78.95
+2020-03-05 03:00:00,1.57,0.0,-0.0,0.0,3.38,82.0
+2020-03-05 04:00:00,1.49,0.0,-0.0,0.0,3.17,82.0
+2020-03-05 05:00:00,1.49,0.0,-0.0,0.0,3.17,85.25
+2020-03-05 06:00:00,1.31,19.0,14.49,18.0,2.97,85.25
+2020-03-05 07:00:00,1.68,154.0,302.47,87.0,2.9,82.05
+2020-03-05 08:00:00,2.95,278.0,384.54,142.0,2.97,79.1
+2020-03-05 09:00:00,4.89,409.0,565.18,151.0,3.03,76.3
+2020-03-05 10:00:00,6.38,395.0,288.73,244.0,2.9,70.95
+2020-03-05 11:00:00,8.23,441.0,359.1,244.0,2.83,63.7
+2020-03-05 12:00:00,8.77,389.0,253.95,254.0,2.69,61.45
+2020-03-05 13:00:00,9.33,345.0,262.08,221.0,2.48,59.25
+2020-03-05 14:00:00,9.5,116.0,2.65,115.0,2.69,61.55
+2020-03-05 15:00:00,8.99,55.0,0.0,55.0,2.62,61.45
+2020-03-05 16:00:00,7.9,23.0,0.0,23.0,2.14,68.6
+2020-03-05 17:00:00,6.42,0.0,-0.0,0.0,2.0,73.7
+2020-03-05 18:00:00,5.5,0.0,-0.0,0.0,1.86,79.35
+2020-03-05 19:00:00,4.51,0.0,-0.0,0.0,1.72,85.5
+2020-03-05 20:00:00,3.57,0.0,-0.0,0.0,1.52,92.15
+2020-03-05 21:00:00,2.81,0.0,-0.0,0.0,1.52,88.7
+2020-03-05 22:00:00,2.27,0.0,-0.0,0.0,1.45,92.15
+2020-03-05 23:00:00,1.96,0.0,-0.0,0.0,1.38,92.1
+2020-03-06 00:00:00,2.11,0.0,-0.0,0.0,1.38,95.65
+2020-03-06 01:00:00,2.25,0.0,-0.0,0.0,1.66,92.15
+2020-03-06 02:00:00,2.42,0.0,-0.0,0.0,1.93,95.7
+2020-03-06 03:00:00,2.88,0.0,-0.0,0.0,2.07,95.7
+2020-03-06 04:00:00,2.99,0.0,-0.0,0.0,2.21,99.4
+2020-03-06 05:00:00,2.44,0.0,-0.0,0.0,2.48,99.4
+2020-03-06 06:00:00,2.39,12.0,0.0,12.0,3.79,95.7
+2020-03-06 07:00:00,2.05,104.0,52.75,92.0,3.66,95.65
+2020-03-06 08:00:00,2.1,151.0,22.24,143.0,4.14,95.65
+2020-03-06 09:00:00,2.73,127.0,0.0,127.0,5.24,88.7
+2020-03-06 10:00:00,3.62,236.0,24.58,223.0,4.97,88.7
+2020-03-06 11:00:00,4.57,250.0,23.45,237.0,5.1,79.2
+2020-03-06 12:00:00,5.79,161.0,0.0,161.0,5.03,65.65
+2020-03-06 13:00:00,6.47,59.0,0.0,59.0,4.83,58.55
+2020-03-06 14:00:00,6.9,70.0,0.0,70.0,4.48,54.3
+2020-03-06 15:00:00,6.9,44.0,0.0,44.0,3.31,54.3
+2020-03-06 16:00:00,6.14,44.0,66.07,37.0,2.07,60.75
+2020-03-06 17:00:00,4.83,0.0,-0.0,0.0,1.86,65.4
+2020-03-06 18:00:00,3.24,0.0,-0.0,0.0,2.14,73.2
+2020-03-06 19:00:00,1.85,0.0,-0.0,0.0,1.86,78.95
+2020-03-06 20:00:00,0.45,0.0,-0.0,0.0,2.14,85.15
+2020-03-06 21:00:00,-0.35,0.0,-0.0,0.0,2.34,85.1
+2020-03-06 22:00:00,-0.89,0.0,-0.0,0.0,2.48,85.05
+2020-03-06 23:00:00,-0.89,0.0,-0.0,0.0,2.55,85.05
+2020-03-07 00:00:00,-0.76,0.0,-0.0,0.0,2.69,88.45
+2020-03-07 01:00:00,-0.53,0.0,-0.0,0.0,2.76,88.45
+2020-03-07 02:00:00,-0.54,0.0,-0.0,0.0,2.62,88.45
+2020-03-07 03:00:00,-0.82,0.0,-0.0,0.0,2.41,88.45
+2020-03-07 04:00:00,-1.24,0.0,-0.0,0.0,2.28,88.4
+2020-03-07 05:00:00,-1.61,0.0,-0.0,0.0,2.21,88.35
+2020-03-07 06:00:00,-1.69,28.0,37.05,25.0,2.07,88.35
+2020-03-07 07:00:00,0.25,190.0,496.73,74.0,1.79,88.5
+2020-03-07 08:00:00,2.62,318.0,533.29,123.0,2.48,79.0
+2020-03-07 09:00:00,3.66,378.0,377.92,201.0,2.83,70.5
+2020-03-07 10:00:00,4.62,253.0,31.8,236.0,2.07,67.9
+2020-03-07 11:00:00,5.32,358.0,139.3,280.0,1.38,63.05
+2020-03-07 12:00:00,5.51,109.0,0.0,109.0,0.97,63.05
+2020-03-07 13:00:00,5.26,171.0,4.13,169.0,0.83,63.05
+2020-03-07 14:00:00,5.42,222.0,103.25,182.0,0.62,63.05
+2020-03-07 15:00:00,5.3,142.0,107.61,114.0,0.69,63.05
+2020-03-07 16:00:00,4.98,72.0,343.25,34.0,0.9,65.4
+2020-03-07 17:00:00,4.06,0.0,-0.0,0.0,1.45,73.3
+2020-03-07 18:00:00,2.17,0.0,-0.0,0.0,1.45,82.15
+2020-03-07 19:00:00,2.35,0.0,-0.0,0.0,0.21,82.15
+2020-03-07 20:00:00,2.03,0.0,-0.0,0.0,0.41,85.3
+2020-03-07 21:00:00,1.72,0.0,-0.0,0.0,0.62,85.3
+2020-03-07 22:00:00,1.42,0.0,-0.0,0.0,0.48,85.25
+2020-03-07 23:00:00,1.15,0.0,-0.0,0.0,0.48,85.25
+2020-03-08 00:00:00,0.87,0.0,-0.0,0.0,0.69,88.55
+2020-03-08 01:00:00,0.65,0.0,-0.0,0.0,0.9,85.2
+2020-03-08 02:00:00,0.42,0.0,-0.0,0.0,0.97,88.5
+2020-03-08 03:00:00,-0.86,0.0,-0.0,0.0,1.17,91.95
+2020-03-08 04:00:00,-1.79,0.0,-0.0,0.0,1.52,95.6
+2020-03-08 05:00:00,-2.27,0.0,-0.0,0.0,1.66,95.55
+2020-03-08 06:00:00,-2.02,6.0,0.0,6.0,1.45,99.4
+2020-03-08 07:00:00,-0.67,0.0,0.0,0.0,1.17,95.6
+2020-03-08 08:00:00,1.41,167.0,32.29,155.0,1.72,88.6
+2020-03-08 09:00:00,2.62,164.0,4.22,162.0,1.86,88.65
+2020-03-08 10:00:00,3.39,345.0,142.48,268.0,2.0,85.4
+2020-03-08 11:00:00,4.29,452.0,341.23,259.0,2.41,73.4
+2020-03-08 12:00:00,4.97,213.0,9.12,208.0,2.34,68.0
+2020-03-08 13:00:00,5.34,116.0,0.0,116.0,2.41,63.05
+2020-03-08 14:00:00,5.52,108.0,0.0,108.0,2.34,63.05
+2020-03-08 15:00:00,5.51,130.0,64.13,113.0,2.28,63.05
+2020-03-08 16:00:00,5.04,47.0,51.97,41.0,1.59,65.4
+2020-03-08 17:00:00,3.74,0.0,-0.0,0.0,1.24,76.15
+2020-03-08 18:00:00,3.38,0.0,-0.0,0.0,0.97,73.2
+2020-03-08 19:00:00,1.7,0.0,-0.0,0.0,1.1,78.95
+2020-03-08 20:00:00,-0.13,0.0,-0.0,0.0,1.52,85.1
+2020-03-08 21:00:00,-0.94,0.0,-0.0,0.0,1.66,88.4
+2020-03-08 22:00:00,-1.43,0.0,-0.0,0.0,1.66,88.35
+2020-03-08 23:00:00,-1.27,0.0,-0.0,0.0,1.59,85.0
+2020-03-09 00:00:00,-1.55,0.0,-0.0,0.0,1.52,88.35
+2020-03-09 01:00:00,-2.03,0.0,-0.0,0.0,1.52,91.85
+2020-03-09 02:00:00,-2.35,0.0,-0.0,0.0,1.45,88.3
+2020-03-09 03:00:00,-2.55,0.0,-0.0,0.0,1.45,91.85
+2020-03-09 04:00:00,-2.74,0.0,-0.0,0.0,1.52,91.85
+2020-03-09 05:00:00,-2.84,0.0,-0.0,0.0,1.59,88.25
+2020-03-09 06:00:00,-2.77,38.0,64.49,32.0,1.59,88.25
+2020-03-09 07:00:00,-1.12,0.0,0.0,0.0,1.31,95.6
+2020-03-09 08:00:00,3.19,315.0,452.74,144.0,1.24,82.2
+2020-03-09 09:00:00,5.16,468.0,722.57,121.0,2.14,68.1
+2020-03-09 10:00:00,6.19,553.0,787.19,123.0,3.24,60.85
+2020-03-09 11:00:00,6.74,567.0,729.99,150.0,3.59,56.45
+2020-03-09 12:00:00,7.14,446.0,350.48,252.0,3.59,54.3
+2020-03-09 13:00:00,7.17,490.0,758.67,115.0,3.52,52.2
+2020-03-09 14:00:00,7.15,377.0,694.21,101.0,3.59,50.2
+2020-03-09 15:00:00,6.88,124.0,48.15,111.0,3.38,50.2
+2020-03-09 16:00:00,6.12,52.0,66.56,44.0,2.62,56.2
+2020-03-09 17:00:00,4.9,0.0,-0.0,0.0,2.28,62.95
+2020-03-09 18:00:00,3.77,0.0,-0.0,0.0,2.21,67.8
+2020-03-09 19:00:00,2.75,0.0,-0.0,0.0,2.0,73.2
+2020-03-09 20:00:00,1.94,0.0,-0.0,0.0,1.93,82.05
+2020-03-09 21:00:00,1.24,0.0,-0.0,0.0,2.0,85.25
+2020-03-09 22:00:00,0.63,0.0,-0.0,0.0,2.07,85.2
+2020-03-09 23:00:00,0.41,0.0,-0.0,0.0,1.93,88.5
+2020-03-10 00:00:00,0.13,0.0,-0.0,0.0,1.86,88.5
+2020-03-10 01:00:00,0.41,0.0,-0.0,0.0,1.66,92.0
+2020-03-10 02:00:00,0.31,0.0,-0.0,0.0,1.52,92.0
+2020-03-10 03:00:00,-0.14,0.0,-0.0,0.0,1.38,92.0
+2020-03-10 04:00:00,-0.04,0.0,-0.0,0.0,1.31,95.6
+2020-03-10 05:00:00,-0.08,0.0,-0.0,0.0,1.31,95.6
+2020-03-10 06:00:00,-0.01,34.0,30.27,31.0,1.31,95.6
+2020-03-10 07:00:00,1.43,90.0,11.92,87.0,0.97,95.65
+2020-03-10 08:00:00,3.21,113.0,0.0,113.0,1.72,88.7
+2020-03-10 09:00:00,4.5,109.0,0.0,109.0,2.0,85.5
+2020-03-10 10:00:00,5.35,91.0,0.0,91.0,2.34,79.35
+2020-03-10 11:00:00,6.19,114.0,0.0,114.0,2.62,73.7
+2020-03-10 12:00:00,6.76,77.0,0.0,77.0,2.76,73.8
+2020-03-10 13:00:00,7.16,129.0,0.0,129.0,2.83,73.8
+2020-03-10 14:00:00,7.23,142.0,4.97,140.0,2.9,73.9
+2020-03-10 15:00:00,7.05,59.0,0.0,59.0,2.76,76.65
+2020-03-10 16:00:00,6.69,46.0,32.02,42.0,2.83,76.65
+2020-03-10 17:00:00,6.01,0.0,-0.0,0.0,2.76,79.4
+2020-03-10 18:00:00,5.56,0.0,-0.0,0.0,2.69,79.35
+2020-03-10 19:00:00,5.04,0.0,-0.0,0.0,2.34,82.35
+2020-03-10 20:00:00,4.6,0.0,-0.0,0.0,2.14,85.5
+2020-03-10 21:00:00,4.14,0.0,-0.0,0.0,1.93,85.5
+2020-03-10 22:00:00,3.51,0.0,-0.0,0.0,1.66,95.7
+2020-03-10 23:00:00,3.07,0.0,-0.0,0.0,1.52,92.15
+2020-03-11 00:00:00,2.59,0.0,-0.0,0.0,1.31,95.7
+2020-03-11 01:00:00,2.49,0.0,-0.0,0.0,1.24,95.7
+2020-03-11 02:00:00,2.4,0.0,-0.0,0.0,1.24,95.7
+2020-03-11 03:00:00,2.23,0.0,-0.0,0.0,1.24,95.7
+2020-03-11 04:00:00,2.31,0.0,-0.0,0.0,1.31,95.7
+2020-03-11 05:00:00,2.14,0.0,-0.0,0.0,1.38,95.7
+2020-03-11 06:00:00,1.93,23.0,0.0,23.0,1.38,95.65
+2020-03-11 07:00:00,2.35,75.0,0.0,75.0,1.45,95.7
+2020-03-11 08:00:00,3.24,124.0,2.57,123.0,1.93,92.15
+2020-03-11 09:00:00,4.04,211.0,18.29,202.0,2.28,88.75
+2020-03-11 10:00:00,4.82,163.0,0.0,163.0,3.17,76.3
+2020-03-11 11:00:00,5.86,117.0,0.0,117.0,3.45,65.65
+2020-03-11 12:00:00,5.73,68.0,0.0,68.0,3.31,65.65
+2020-03-11 13:00:00,5.84,61.0,0.0,61.0,3.1,65.65
+2020-03-11 14:00:00,5.52,67.0,0.0,67.0,2.83,68.1
+2020-03-11 15:00:00,5.34,47.0,0.0,47.0,2.97,70.8
+2020-03-11 16:00:00,4.94,34.0,7.71,33.0,2.76,73.45
+2020-03-11 17:00:00,4.35,0.0,-0.0,0.0,2.55,76.25
+2020-03-11 18:00:00,3.65,0.0,-0.0,0.0,2.34,79.15
+2020-03-11 19:00:00,3.21,0.0,-0.0,0.0,2.28,82.2
+2020-03-11 20:00:00,2.83,0.0,-0.0,0.0,2.21,82.2
+2020-03-11 21:00:00,2.37,0.0,-0.0,0.0,2.14,85.35
+2020-03-11 22:00:00,1.88,0.0,-0.0,0.0,1.93,88.65
+2020-03-11 23:00:00,1.61,0.0,-0.0,0.0,1.79,92.05
+2020-03-12 00:00:00,1.42,0.0,-0.0,0.0,0.0,92.05
+2020-03-12 01:00:00,1.3,0.0,-0.0,0.0,0.0,88.6
+2020-03-12 02:00:00,1.27,0.0,-0.0,0.0,1.79,92.05
+2020-03-12 03:00:00,1.29,0.0,-0.0,0.0,1.52,92.05
+2020-03-12 04:00:00,1.25,0.0,-0.0,0.0,1.45,95.65
+2020-03-12 05:00:00,1.26,0.0,-0.0,0.0,1.66,95.65
+2020-03-12 06:00:00,1.31,20.0,0.0,20.0,2.14,92.05
+2020-03-12 07:00:00,1.53,62.0,0.0,62.0,2.41,92.05
+2020-03-12 08:00:00,1.84,97.0,0.0,97.0,2.69,88.65
+2020-03-12 09:00:00,2.2,87.0,0.0,87.0,2.83,82.15
+2020-03-12 10:00:00,2.26,92.0,0.0,92.0,2.69,82.15
+2020-03-12 11:00:00,2.5,106.0,0.0,106.0,2.55,82.15
+2020-03-12 12:00:00,2.93,66.0,0.0,66.0,2.48,79.1
+2020-03-12 13:00:00,2.94,83.0,0.0,83.0,2.41,79.1
+2020-03-12 14:00:00,2.99,121.0,0.0,121.0,2.34,79.1
+2020-03-12 15:00:00,3.1,94.0,7.03,92.0,2.62,79.1
+2020-03-12 16:00:00,2.97,41.0,7.44,40.0,2.69,79.1
+2020-03-12 17:00:00,2.71,0.0,-0.0,0.0,2.14,79.1
+2020-03-12 18:00:00,2.51,0.0,-0.0,0.0,2.14,85.35
+2020-03-12 19:00:00,1.99,0.0,-0.0,0.0,2.07,88.65
+2020-03-12 20:00:00,1.79,0.0,-0.0,0.0,1.93,88.65
+2020-03-12 21:00:00,1.64,0.0,-0.0,0.0,1.79,88.65
+2020-03-12 22:00:00,1.48,0.0,-0.0,0.0,1.72,92.05
+2020-03-12 23:00:00,1.3,0.0,-0.0,0.0,2.0,92.05
+2020-03-13 00:00:00,1.24,0.0,-0.0,0.0,2.07,92.05
+2020-03-13 01:00:00,0.99,0.0,-0.0,0.0,1.38,99.35
+2020-03-13 02:00:00,1.0,0.0,-0.0,0.0,1.59,99.35
+2020-03-13 03:00:00,0.99,0.0,-0.0,0.0,1.59,99.35
+2020-03-13 04:00:00,1.02,0.0,-0.0,0.0,1.66,99.35
+2020-03-13 05:00:00,0.99,0.0,-0.0,0.0,1.93,99.35
+2020-03-13 06:00:00,0.96,14.0,0.0,14.0,2.41,95.65
+2020-03-13 07:00:00,0.91,60.0,0.0,60.0,2.62,92.05
+2020-03-13 08:00:00,1.27,72.0,0.0,72.0,2.83,92.05
+2020-03-13 09:00:00,1.5,80.0,0.0,80.0,3.1,92.05
+2020-03-13 10:00:00,1.59,69.0,0.0,69.0,3.24,88.6
+2020-03-13 11:00:00,1.88,65.0,0.0,65.0,3.31,85.3
+2020-03-13 12:00:00,1.7,58.0,0.0,58.0,3.24,82.05
+2020-03-13 13:00:00,2.02,69.0,0.0,69.0,3.1,82.05
+2020-03-13 14:00:00,2.46,59.0,0.0,59.0,3.1,79.0
+2020-03-13 15:00:00,2.35,35.0,0.0,35.0,3.03,79.0
+2020-03-13 16:00:00,2.16,23.0,0.0,23.0,2.9,79.0
+2020-03-13 17:00:00,1.95,0.0,-0.0,0.0,2.62,85.3
+2020-03-13 18:00:00,1.71,0.0,-0.0,0.0,2.48,85.3
+2020-03-13 19:00:00,0.84,0.0,-0.0,0.0,2.62,85.2
+2020-03-13 20:00:00,0.65,0.0,-0.0,0.0,2.28,85.2
+2020-03-13 21:00:00,0.41,0.0,-0.0,0.0,1.86,88.5
+2020-03-13 22:00:00,-0.09,0.0,-0.0,0.0,2.14,92.0
+2020-03-13 23:00:00,-0.31,0.0,-0.0,0.0,1.93,92.0
+2020-03-14 00:00:00,-0.38,0.0,-0.0,0.0,2.0,88.45
+2020-03-14 01:00:00,-0.85,0.0,-0.0,0.0,2.0,88.45
+2020-03-14 02:00:00,-1.23,0.0,-0.0,0.0,1.93,91.95
+2020-03-14 03:00:00,-1.65,0.0,-0.0,0.0,1.72,91.9
+2020-03-14 04:00:00,-1.9,0.0,-0.0,0.0,1.52,91.9
+2020-03-14 05:00:00,-2.47,0.0,-0.0,0.0,1.38,95.55
+2020-03-14 06:00:00,-2.15,43.0,24.27,40.0,1.38,95.55
+2020-03-14 07:00:00,-0.76,196.0,289.69,116.0,1.93,88.45
+2020-03-14 08:00:00,0.16,355.0,509.94,147.0,2.07,81.9
+2020-03-14 09:00:00,1.25,245.0,35.3,227.0,2.48,78.9
+2020-03-14 10:00:00,2.24,231.0,8.69,226.0,2.14,73.1
+2020-03-14 11:00:00,2.99,409.0,176.9,303.0,1.66,70.4
+2020-03-14 12:00:00,4.02,466.0,341.1,268.0,1.79,67.8
+2020-03-14 13:00:00,4.6,523.0,776.58,119.0,2.14,67.9
+2020-03-14 14:00:00,4.75,407.0,714.7,105.0,2.0,65.4
+2020-03-14 15:00:00,4.56,241.0,469.2,103.0,1.93,65.3
+2020-03-14 16:00:00,3.92,85.0,208.82,55.0,2.28,67.8
+2020-03-14 17:00:00,2.86,0.0,-0.0,0.0,1.86,70.4
+2020-03-14 18:00:00,1.83,0.0,-0.0,0.0,1.72,75.95
+2020-03-14 19:00:00,1.85,0.0,-0.0,0.0,1.66,78.95
+2020-03-14 20:00:00,1.38,0.0,-0.0,0.0,1.72,82.0
+2020-03-14 21:00:00,1.19,0.0,-0.0,0.0,1.79,82.0
+2020-03-14 22:00:00,1.17,0.0,-0.0,0.0,1.86,82.0
+2020-03-14 23:00:00,1.12,0.0,-0.0,0.0,2.0,82.0
+2020-03-15 00:00:00,1.19,0.0,-0.0,0.0,2.14,82.0
+2020-03-15 01:00:00,1.51,0.0,-0.0,0.0,2.28,85.25
+2020-03-15 02:00:00,1.44,0.0,-0.0,0.0,2.48,88.6
+2020-03-15 03:00:00,1.23,0.0,-0.0,0.0,2.62,92.05
+2020-03-15 04:00:00,0.99,0.0,-0.0,0.0,2.76,95.65
+2020-03-15 05:00:00,0.83,0.0,-0.0,0.0,2.62,95.65
+2020-03-15 06:00:00,0.81,26.0,0.0,26.0,2.41,95.65
+2020-03-15 07:00:00,0.94,21.0,0.0,21.0,2.48,95.65
+2020-03-15 08:00:00,1.46,108.0,0.0,108.0,3.03,95.65
+2020-03-15 09:00:00,2.84,124.0,0.0,124.0,3.72,79.1
+2020-03-15 10:00:00,3.53,175.0,0.0,175.0,3.93,79.1
+2020-03-15 11:00:00,4.28,110.0,0.0,110.0,4.21,76.25
+2020-03-15 12:00:00,4.46,80.0,0.0,80.0,4.14,76.25
+2020-03-15 13:00:00,4.44,80.0,0.0,80.0,4.28,73.4
+2020-03-15 14:00:00,4.33,49.0,0.0,49.0,4.34,76.25
+2020-03-15 15:00:00,4.23,66.0,0.0,66.0,4.21,76.25
+2020-03-15 16:00:00,3.77,49.0,13.49,47.0,3.31,79.15
+2020-03-15 17:00:00,2.83,0.0,-0.0,0.0,2.69,85.4
+2020-03-15 18:00:00,2.15,0.0,-0.0,0.0,2.69,88.65
+2020-03-15 19:00:00,1.36,0.0,-0.0,0.0,2.69,92.05
+2020-03-15 20:00:00,1.25,0.0,-0.0,0.0,2.76,92.05
+2020-03-15 21:00:00,1.28,0.0,-0.0,0.0,3.03,92.05
+2020-03-15 22:00:00,1.02,0.0,-0.0,0.0,3.1,92.05
+2020-03-15 23:00:00,0.68,0.0,-0.0,0.0,2.97,88.55
+2020-03-16 00:00:00,0.6,0.0,-0.0,0.0,2.97,92.0
+2020-03-16 01:00:00,0.79,0.0,-0.0,0.0,2.83,88.55
+2020-03-16 02:00:00,0.54,0.0,-0.0,0.0,2.76,92.0
+2020-03-16 03:00:00,0.01,0.0,-0.0,0.0,2.69,92.0
+2020-03-16 04:00:00,-0.05,0.0,-0.0,0.0,2.9,92.0
+2020-03-16 05:00:00,-0.09,0.0,-0.0,0.0,2.9,92.0
+2020-03-16 06:00:00,-0.2,81.0,220.64,51.0,3.38,92.0
+2020-03-16 07:00:00,0.85,226.0,409.15,108.0,3.66,85.2
+2020-03-16 08:00:00,1.64,390.0,650.08,117.0,3.79,78.95
+2020-03-16 09:00:00,2.99,466.0,532.94,188.0,3.72,73.2
+2020-03-16 10:00:00,4.65,395.0,173.9,293.0,3.59,65.4
+2020-03-16 11:00:00,6.42,575.0,612.9,201.0,3.86,58.55
+2020-03-16 12:00:00,7.52,399.0,174.26,296.0,3.79,54.4
+2020-03-16 13:00:00,8.08,260.0,39.59,239.0,3.86,52.45
+2020-03-16 14:00:00,8.27,104.0,0.0,104.0,3.79,50.6
+2020-03-16 15:00:00,7.9,74.0,0.0,74.0,3.38,52.45
+2020-03-16 16:00:00,7.43,70.0,71.92,59.0,2.83,56.55
+2020-03-16 17:00:00,6.35,0.0,-0.0,0.0,2.48,60.85
+2020-03-16 18:00:00,4.69,0.0,-0.0,0.0,2.34,68.0
+2020-03-16 19:00:00,3.63,0.0,-0.0,0.0,2.28,76.1
+2020-03-16 20:00:00,2.53,0.0,-0.0,0.0,2.21,79.0
+2020-03-16 21:00:00,1.32,0.0,-0.0,0.0,2.14,85.25
+2020-03-16 22:00:00,0.28,0.0,-0.0,0.0,2.07,88.5
+2020-03-16 23:00:00,-0.63,0.0,-0.0,0.0,2.0,91.95
+2020-03-17 00:00:00,-1.32,0.0,-0.0,0.0,1.93,91.95
+2020-03-17 01:00:00,-1.95,0.0,-0.0,0.0,1.86,95.55
+2020-03-17 02:00:00,-2.17,0.0,-0.0,0.0,1.79,91.85
+2020-03-17 03:00:00,-2.37,0.0,-0.0,0.0,1.79,91.85
+2020-03-17 04:00:00,-2.55,0.0,-0.0,0.0,1.79,95.55
+2020-03-17 05:00:00,-2.6,0.0,-0.0,0.0,1.72,95.55
+2020-03-17 06:00:00,-1.99,90.0,267.33,52.0,1.52,95.55
+2020-03-17 07:00:00,1.12,261.0,611.15,81.0,1.03,85.25
+2020-03-17 08:00:00,4.61,417.0,751.24,97.0,0.97,79.2
+2020-03-17 09:00:00,6.44,534.0,796.21,114.0,1.1,70.95
+2020-03-17 10:00:00,7.77,616.0,842.61,117.0,1.1,63.6
+2020-03-17 11:00:00,8.89,645.0,854.33,119.0,1.03,59.15
+2020-03-17 12:00:00,9.7,517.0,454.44,246.0,0.83,55.05
+2020-03-17 13:00:00,10.22,558.0,855.32,100.0,0.48,53.1
+2020-03-17 14:00:00,10.41,428.0,750.16,100.0,0.41,53.1
+2020-03-17 15:00:00,10.25,275.0,616.2,85.0,0.9,53.1
+2020-03-17 16:00:00,9.49,116.0,431.6,48.0,1.38,59.25
+2020-03-17 17:00:00,7.67,0.0,-0.0,0.0,1.86,68.5
+2020-03-17 18:00:00,5.64,0.0,-0.0,0.0,1.66,79.35
+2020-03-17 19:00:00,6.6,0.0,-0.0,0.0,0.69,65.75
+2020-03-17 20:00:00,6.28,0.0,-0.0,0.0,0.28,65.75
+2020-03-17 21:00:00,5.62,0.0,-0.0,0.0,1.17,70.8
+2020-03-17 22:00:00,1.65,0.0,-0.0,0.0,1.79,78.95
+2020-03-17 23:00:00,0.15,0.0,-0.0,0.0,2.0,85.15
+2020-03-18 00:00:00,-0.76,0.0,-0.0,0.0,2.0,88.45
+2020-03-18 01:00:00,-1.41,0.0,-0.0,0.0,2.07,91.9
+2020-03-18 02:00:00,-1.5,0.0,-0.0,0.0,2.14,91.9
+2020-03-18 03:00:00,-1.48,0.0,-0.0,0.0,2.28,91.9
+2020-03-18 04:00:00,-1.39,0.0,-0.0,0.0,2.34,88.4
+2020-03-18 05:00:00,-1.26,0.0,-0.0,0.0,2.41,88.4
+2020-03-18 06:00:00,-0.58,91.0,235.96,56.0,2.48,88.45
+2020-03-18 07:00:00,2.71,256.0,545.49,92.0,2.62,79.1
+2020-03-18 08:00:00,4.64,409.0,694.5,109.0,3.52,76.25
+2020-03-18 09:00:00,5.44,530.0,768.74,120.0,4.0,70.8
+2020-03-18 10:00:00,6.09,604.0,787.81,133.0,4.07,68.2
+2020-03-18 11:00:00,6.68,643.0,835.58,124.0,4.0,65.85
+2020-03-18 12:00:00,7.1,489.0,364.05,270.0,4.0,68.4
+2020-03-18 13:00:00,7.13,527.0,716.02,140.0,4.0,71.05
+2020-03-18 14:00:00,6.78,223.0,54.29,199.0,3.79,71.05
+2020-03-18 15:00:00,6.11,81.0,0.0,81.0,3.52,76.5
+2020-03-18 16:00:00,5.47,60.0,24.67,56.0,3.17,76.4
+2020-03-18 17:00:00,4.85,0.0,-0.0,0.0,2.41,79.3
+2020-03-18 18:00:00,4.13,0.0,-0.0,0.0,2.0,85.45
+2020-03-18 19:00:00,3.44,0.0,-0.0,0.0,2.0,88.7
+2020-03-18 20:00:00,3.19,0.0,-0.0,0.0,1.86,88.7
+2020-03-18 21:00:00,3.12,0.0,-0.0,0.0,1.72,88.7
+2020-03-18 22:00:00,3.1,0.0,-0.0,0.0,1.52,92.15
+2020-03-18 23:00:00,3.01,0.0,-0.0,0.0,1.31,92.15
+2020-03-19 00:00:00,3.05,0.0,-0.0,0.0,1.24,92.15
+2020-03-19 01:00:00,3.47,0.0,-0.0,0.0,1.24,99.4
+2020-03-19 02:00:00,3.46,0.0,-0.0,0.0,1.24,99.4
+2020-03-19 03:00:00,3.4,0.0,-0.0,0.0,1.31,99.4
+2020-03-19 04:00:00,3.55,0.0,-0.0,0.0,1.45,99.4
+2020-03-19 05:00:00,3.51,0.0,-0.0,0.0,1.45,100.0
+2020-03-19 06:00:00,3.54,48.0,12.94,46.0,1.93,100.0
+2020-03-19 07:00:00,3.46,89.0,0.0,89.0,2.07,100.0
+2020-03-19 08:00:00,3.62,132.0,0.0,132.0,2.0,100.0
+2020-03-19 09:00:00,3.99,190.0,3.71,188.0,1.79,99.4
+2020-03-19 10:00:00,4.89,174.0,0.0,174.0,1.93,88.85
+2020-03-19 11:00:00,5.59,315.0,41.5,289.0,2.07,82.4
+2020-03-19 12:00:00,6.42,331.0,67.57,290.0,2.41,76.55
+2020-03-19 13:00:00,6.54,207.0,7.33,203.0,2.34,76.55
+2020-03-19 14:00:00,6.69,221.0,49.23,199.0,2.69,71.05
+2020-03-19 15:00:00,6.66,195.0,160.53,144.0,2.62,68.4
+2020-03-19 16:00:00,6.24,96.0,173.94,67.0,2.07,70.95
+2020-03-19 17:00:00,5.52,0.0,0.0,0.0,1.72,79.35
+2020-03-19 18:00:00,4.78,0.0,-0.0,0.0,1.72,79.3
+2020-03-19 19:00:00,4.28,0.0,-0.0,0.0,2.07,88.8
+2020-03-19 20:00:00,4.07,0.0,-0.0,0.0,2.07,88.75
+2020-03-19 21:00:00,3.91,0.0,-0.0,0.0,2.14,88.75
+2020-03-19 22:00:00,3.78,0.0,-0.0,0.0,2.28,85.45
+2020-03-19 23:00:00,3.82,0.0,-0.0,0.0,2.62,85.45
+2020-03-20 00:00:00,3.52,0.0,-0.0,0.0,2.83,85.4
+2020-03-20 01:00:00,3.16,0.0,-0.0,0.0,3.03,82.2
+2020-03-20 02:00:00,2.84,0.0,-0.0,0.0,3.24,82.2
+2020-03-20 03:00:00,2.34,0.0,-0.0,0.0,3.31,85.35
+2020-03-20 04:00:00,2.16,0.0,-0.0,0.0,3.59,85.35
+2020-03-20 05:00:00,1.97,0.0,-0.0,0.0,3.66,88.65
+2020-03-20 06:00:00,2.05,44.0,6.22,43.0,3.66,88.65
+2020-03-20 07:00:00,2.7,89.0,0.0,89.0,3.93,85.4
+2020-03-20 08:00:00,3.12,114.0,0.0,114.0,4.55,82.2
+2020-03-20 09:00:00,3.69,119.0,0.0,119.0,4.83,76.15
+2020-03-20 10:00:00,4.18,112.0,0.0,112.0,4.76,73.4
+2020-03-20 11:00:00,4.67,90.0,0.0,90.0,4.69,70.7
+2020-03-20 12:00:00,5.24,77.0,0.0,77.0,4.76,68.1
+2020-03-20 13:00:00,5.43,282.0,50.87,254.0,4.62,70.8
+2020-03-20 14:00:00,5.53,88.0,0.0,88.0,4.21,70.8
+2020-03-20 15:00:00,5.53,100.0,3.1,99.0,4.62,73.55
+2020-03-20 16:00:00,5.31,63.0,23.35,59.0,3.52,76.4
+2020-03-20 17:00:00,4.99,0.0,0.0,0.0,3.59,79.3
+2020-03-20 18:00:00,4.66,0.0,-0.0,0.0,3.59,79.3
+2020-03-20 19:00:00,4.35,0.0,-0.0,0.0,3.86,82.3
+2020-03-20 20:00:00,4.32,0.0,-0.0,0.0,3.93,85.5
+2020-03-20 21:00:00,4.27,0.0,-0.0,0.0,3.86,85.5
+2020-03-20 22:00:00,4.27,0.0,-0.0,0.0,3.66,88.8
+2020-03-20 23:00:00,4.2,0.0,-0.0,0.0,3.52,92.2
+2020-03-21 00:00:00,4.13,0.0,-0.0,0.0,3.45,95.7
+2020-03-21 01:00:00,4.14,0.0,-0.0,0.0,3.45,95.75
+2020-03-21 02:00:00,3.92,0.0,-0.0,0.0,3.59,99.4
+2020-03-21 03:00:00,3.6,0.0,-0.0,0.0,3.52,99.4
+2020-03-21 04:00:00,3.19,0.0,-0.0,0.0,3.45,95.7
+2020-03-21 05:00:00,2.96,0.0,0.0,0.0,3.31,95.7
+2020-03-21 06:00:00,3.03,68.0,41.95,61.0,3.17,95.7
+2020-03-21 07:00:00,3.87,86.0,0.0,86.0,3.38,95.7
+2020-03-21 08:00:00,4.58,224.0,51.13,201.0,4.0,92.2
+2020-03-21 09:00:00,4.7,212.0,7.26,208.0,3.79,92.25
+2020-03-21 10:00:00,5.32,198.0,1.63,197.0,3.38,88.85
+2020-03-21 11:00:00,6.31,106.0,0.0,106.0,3.93,79.5
+2020-03-21 12:00:00,7.27,123.0,0.0,123.0,4.83,71.15
+2020-03-21 13:00:00,7.32,85.0,0.0,85.0,5.03,71.15
+2020-03-21 14:00:00,7.25,150.0,2.19,149.0,5.1,68.5
+2020-03-21 15:00:00,7.32,78.0,0.0,78.0,5.03,68.5
+2020-03-21 16:00:00,6.79,60.0,17.06,57.0,4.0,73.8
+2020-03-21 17:00:00,6.12,0.0,0.0,0.0,3.72,79.4
+2020-03-21 18:00:00,5.5,0.0,-0.0,0.0,3.93,85.6
+2020-03-21 19:00:00,4.81,0.0,-0.0,0.0,4.0,88.85
+2020-03-21 20:00:00,4.4,0.0,-0.0,0.0,4.14,92.2
+2020-03-21 21:00:00,4.24,0.0,-0.0,0.0,4.0,92.2
+2020-03-21 22:00:00,4.09,0.0,-0.0,0.0,4.07,95.7
+2020-03-21 23:00:00,3.94,0.0,-0.0,0.0,4.21,95.7
+2020-03-22 00:00:00,3.75,0.0,-0.0,0.0,4.14,95.7
+2020-03-22 01:00:00,3.6,0.0,-0.0,0.0,4.0,99.4
+2020-03-22 02:00:00,3.43,0.0,-0.0,0.0,3.72,99.4
+2020-03-22 03:00:00,3.35,0.0,-0.0,0.0,3.59,99.4
+2020-03-22 04:00:00,3.24,0.0,-0.0,0.0,3.79,95.7
+2020-03-22 05:00:00,3.07,0.0,0.0,0.0,3.72,92.15
+2020-03-22 06:00:00,3.04,60.0,17.34,57.0,4.14,92.15
+2020-03-22 07:00:00,3.74,124.0,15.38,119.0,2.76,95.7
+2020-03-22 08:00:00,4.57,192.0,19.75,183.0,0.0,99.4
+2020-03-22 09:00:00,5.38,176.0,0.0,176.0,0.0,95.75
+2020-03-22 10:00:00,6.06,122.0,0.0,122.0,3.38,92.3
+2020-03-22 11:00:00,6.63,405.0,129.17,322.0,3.03,92.3
+2020-03-22 12:00:00,7.14,187.0,0.0,187.0,3.1,89.0
+2020-03-22 13:00:00,7.7,50.0,0.0,50.0,3.31,79.7
+2020-03-22 14:00:00,7.17,220.0,39.04,202.0,3.31,79.65
+2020-03-22 15:00:00,7.09,162.0,57.31,143.0,2.97,82.6
+2020-03-22 16:00:00,6.42,89.0,94.27,72.0,2.83,79.5
+2020-03-22 17:00:00,5.48,0.0,0.0,0.0,2.07,85.6
+2020-03-22 18:00:00,4.59,0.0,-0.0,0.0,1.79,92.2
+2020-03-22 19:00:00,3.98,0.0,-0.0,0.0,1.93,92.15
+2020-03-22 20:00:00,3.8,0.0,-0.0,0.0,1.79,92.15
+2020-03-22 21:00:00,3.34,0.0,-0.0,0.0,1.72,95.7
+2020-03-22 22:00:00,3.16,0.0,-0.0,0.0,1.59,95.7
+2020-03-22 23:00:00,2.93,0.0,-0.0,0.0,1.52,92.15
+2020-03-23 00:00:00,2.55,0.0,-0.0,0.0,1.59,95.7
+2020-03-23 01:00:00,2.68,0.0,-0.0,0.0,1.59,92.15
+2020-03-23 02:00:00,2.85,0.0,-0.0,0.0,1.59,92.15
+2020-03-23 03:00:00,2.92,0.0,-0.0,0.0,1.52,95.7
+2020-03-23 04:00:00,2.98,0.0,-0.0,0.0,1.52,95.7
+2020-03-23 05:00:00,2.74,0.0,0.0,0.0,1.45,95.7
+2020-03-23 06:00:00,2.92,126.0,351.54,63.0,1.45,95.7
+2020-03-23 07:00:00,3.83,142.0,30.21,132.0,2.21,95.7
+2020-03-23 08:00:00,4.64,275.0,119.13,220.0,2.21,92.2
+2020-03-23 09:00:00,5.49,291.0,53.37,261.0,2.62,82.4
+2020-03-23 10:00:00,6.41,393.0,127.87,313.0,2.9,70.95
+2020-03-23 11:00:00,7.21,91.0,0.0,91.0,3.38,63.5
+2020-03-23 12:00:00,7.37,161.0,0.0,161.0,3.72,63.5
+2020-03-23 13:00:00,7.22,113.0,0.0,113.0,4.0,65.95
+2020-03-23 14:00:00,7.0,110.0,0.0,110.0,4.14,65.85
+2020-03-23 15:00:00,6.54,71.0,0.0,71.0,3.79,70.95
+2020-03-23 16:00:00,5.7,63.0,16.23,60.0,2.97,76.5
+2020-03-23 17:00:00,5.03,0.0,0.0,0.0,2.83,82.35
+2020-03-23 18:00:00,4.21,0.0,-0.0,0.0,2.62,85.5
+2020-03-23 19:00:00,3.88,0.0,-0.0,0.0,2.41,85.45
+2020-03-23 20:00:00,3.7,0.0,-0.0,0.0,2.28,85.45
+2020-03-23 21:00:00,3.32,0.0,-0.0,0.0,2.21,88.7
+2020-03-23 22:00:00,2.95,0.0,-0.0,0.0,2.14,88.7
+2020-03-23 23:00:00,2.74,0.0,-0.0,0.0,2.0,88.7
+2020-03-24 00:00:00,2.38,0.0,-0.0,0.0,1.93,92.15
+2020-03-24 01:00:00,2.32,0.0,-0.0,0.0,1.86,92.15
+2020-03-24 02:00:00,1.89,0.0,-0.0,0.0,1.86,95.65
+2020-03-24 03:00:00,1.68,0.0,-0.0,0.0,1.93,95.65
+2020-03-24 04:00:00,1.45,0.0,-0.0,0.0,1.86,99.4
+2020-03-24 05:00:00,1.22,0.0,0.0,0.0,1.72,95.65
+2020-03-24 06:00:00,1.54,83.0,59.34,72.0,2.41,95.65
+2020-03-24 07:00:00,2.14,138.0,20.77,131.0,1.86,95.7
+2020-03-24 08:00:00,2.53,143.0,0.0,143.0,2.55,92.15
+2020-03-24 09:00:00,3.76,125.0,0.0,125.0,2.48,88.75
+2020-03-24 10:00:00,5.28,223.0,3.17,221.0,2.62,79.35
+2020-03-24 11:00:00,6.09,493.0,267.98,318.0,2.76,73.65
+2020-03-24 12:00:00,6.84,475.0,264.18,308.0,2.97,65.85
+2020-03-24 13:00:00,6.98,420.0,254.44,275.0,2.97,65.85
+2020-03-24 14:00:00,6.98,430.0,599.43,148.0,2.83,63.35
+2020-03-24 15:00:00,7.12,301.0,593.0,99.0,2.9,58.65
+2020-03-24 16:00:00,6.72,150.0,496.55,56.0,2.55,56.45
+2020-03-24 17:00:00,6.07,0.0,0.0,0.0,1.66,60.75
+2020-03-24 18:00:00,4.94,0.0,-0.0,0.0,0.97,73.45
+2020-03-24 19:00:00,5.73,0.0,-0.0,0.0,0.62,58.45
+2020-03-24 20:00:00,2.66,0.0,-0.0,0.0,1.59,76.1
+2020-03-24 21:00:00,1.95,0.0,-0.0,0.0,1.72,78.95
+2020-03-24 22:00:00,1.76,0.0,-0.0,0.0,1.93,78.95
+2020-03-24 23:00:00,2.16,0.0,-0.0,0.0,2.0,76.0
+2020-03-25 00:00:00,1.92,0.0,-0.0,0.0,2.0,78.95
+2020-03-25 01:00:00,2.15,0.0,-0.0,0.0,1.93,76.0
+2020-03-25 02:00:00,2.48,0.0,-0.0,0.0,1.86,76.0
+2020-03-25 03:00:00,2.96,0.0,-0.0,0.0,2.0,73.2
+2020-03-25 04:00:00,3.37,0.0,-0.0,0.0,2.07,76.1
+2020-03-25 05:00:00,3.59,0.0,0.0,0.0,2.0,82.2
+2020-03-25 06:00:00,3.93,53.0,5.22,52.0,2.0,85.45
+2020-03-25 07:00:00,5.54,140.0,23.32,132.0,2.07,82.4
+2020-03-25 08:00:00,7.02,296.0,149.98,225.0,3.1,76.65
+2020-03-25 09:00:00,7.87,273.0,34.88,253.0,3.24,68.6
+2020-03-25 10:00:00,8.66,190.0,0.0,190.0,3.24,68.7
+2020-03-25 11:00:00,9.0,187.0,0.0,187.0,3.31,63.8
+2020-03-25 12:00:00,8.81,129.0,0.0,129.0,3.1,66.25
+2020-03-25 13:00:00,8.52,153.0,0.0,153.0,3.17,71.35
+2020-03-25 14:00:00,8.27,136.0,0.0,136.0,3.1,74.05
+2020-03-25 15:00:00,8.03,74.0,0.0,74.0,2.69,76.8
+2020-03-25 16:00:00,7.7,66.0,15.48,63.0,2.69,79.7
+2020-03-25 17:00:00,6.96,1.0,0.0,1.0,2.41,82.6
+2020-03-25 18:00:00,6.24,0.0,-0.0,0.0,2.34,88.95
+2020-03-25 19:00:00,5.44,0.0,-0.0,0.0,2.34,92.25
+2020-03-25 20:00:00,5.13,0.0,-0.0,0.0,2.34,95.75
+2020-03-25 21:00:00,4.89,0.0,-0.0,0.0,2.28,95.75
+2020-03-25 22:00:00,4.67,0.0,-0.0,0.0,2.14,95.75
+2020-03-25 23:00:00,4.56,0.0,-0.0,0.0,2.14,99.4
+2020-03-26 00:00:00,4.46,0.0,-0.0,0.0,2.28,99.4
+2020-03-26 01:00:00,4.15,0.0,-0.0,0.0,2.28,99.4
+2020-03-26 02:00:00,4.11,0.0,-0.0,0.0,2.14,100.0
+2020-03-26 03:00:00,4.17,0.0,-0.0,0.0,2.07,99.4
+2020-03-26 04:00:00,4.29,0.0,-0.0,0.0,2.14,99.4
+2020-03-26 05:00:00,4.44,2.0,0.0,2.0,2.14,99.4
+2020-03-26 06:00:00,4.71,52.0,0.0,52.0,2.07,99.4
+2020-03-26 07:00:00,5.68,96.0,0.0,96.0,3.1,99.4
+2020-03-26 08:00:00,6.37,204.0,18.78,195.0,3.52,95.8
+2020-03-26 09:00:00,6.96,310.0,62.17,274.0,3.17,89.0
+2020-03-26 10:00:00,8.28,247.0,6.23,243.0,3.52,74.05
+2020-03-26 11:00:00,8.85,385.0,87.43,327.0,3.24,71.4
+2020-03-26 12:00:00,9.18,429.0,165.1,323.0,3.03,68.8
+2020-03-26 13:00:00,9.52,437.0,283.07,273.0,2.69,66.35
+2020-03-26 14:00:00,9.96,383.0,373.2,204.0,2.41,61.65
+2020-03-26 15:00:00,10.17,312.0,614.95,97.0,1.72,59.35
+2020-03-26 16:00:00,9.91,155.0,479.33,60.0,1.17,61.65
+2020-03-26 17:00:00,8.89,7.0,0.0,7.0,0.62,79.85
+2020-03-26 18:00:00,8.21,0.0,-0.0,0.0,0.97,66.15
+2020-03-26 19:00:00,4.22,0.0,-0.0,0.0,2.07,85.5
+2020-03-26 20:00:00,2.32,0.0,-0.0,0.0,2.21,88.65
+2020-03-26 21:00:00,1.48,0.0,-0.0,0.0,2.28,88.6
+2020-03-26 22:00:00,1.24,0.0,-0.0,0.0,2.48,88.6
+2020-03-26 23:00:00,1.25,0.0,-0.0,0.0,2.62,88.6
+2020-03-27 00:00:00,1.59,0.0,-0.0,0.0,2.9,88.6
+2020-03-27 01:00:00,2.07,0.0,-0.0,0.0,3.24,88.65
+2020-03-27 02:00:00,2.49,0.0,-0.0,0.0,3.59,85.35
+2020-03-27 03:00:00,2.78,0.0,-0.0,0.0,4.0,82.2
+2020-03-27 04:00:00,3.0,0.0,-0.0,0.0,4.28,82.2
+2020-03-27 05:00:00,3.1,2.0,0.0,2.0,4.48,82.2
+2020-03-27 06:00:00,3.89,140.0,304.37,78.0,4.55,82.25
+2020-03-27 07:00:00,4.34,321.0,630.89,97.0,4.48,85.5
+2020-03-27 08:00:00,6.14,482.0,775.29,106.0,4.97,76.5
+2020-03-27 09:00:00,8.03,543.0,591.83,197.0,5.1,66.05
+2020-03-27 10:00:00,10.01,662.0,800.36,144.0,4.9,59.35
+2020-03-27 11:00:00,11.76,603.0,513.13,260.0,4.34,51.5
+2020-03-27 12:00:00,13.25,552.0,423.55,278.0,3.93,46.35
+2020-03-27 13:00:00,14.1,596.0,811.56,122.0,3.45,48.15
+2020-03-27 14:00:00,14.56,371.0,313.93,219.0,3.1,50.1
+2020-03-27 15:00:00,14.5,196.0,96.03,162.0,2.69,53.95
+2020-03-27 16:00:00,13.04,62.0,4.94,61.0,2.97,62.3
+2020-03-27 17:00:00,11.39,1.0,0.0,1.0,3.59,69.25
+2020-03-27 18:00:00,9.93,0.0,-0.0,0.0,2.9,77.1
+2020-03-27 19:00:00,9.38,0.0,-0.0,0.0,2.14,79.9
+2020-03-27 20:00:00,8.75,0.0,-0.0,0.0,1.72,79.85
+2020-03-27 21:00:00,7.77,0.0,-0.0,0.0,1.45,85.85
+2020-03-27 22:00:00,6.94,0.0,-0.0,0.0,1.45,92.35
+2020-03-27 23:00:00,5.87,0.0,-0.0,0.0,1.59,92.3
+2020-03-28 00:00:00,5.26,0.0,-0.0,0.0,1.59,92.25
+2020-03-28 01:00:00,4.77,0.0,-0.0,0.0,1.72,92.25
+2020-03-28 02:00:00,4.28,0.0,-0.0,0.0,1.79,92.2
+2020-03-28 03:00:00,3.58,0.0,-0.0,0.0,1.86,95.7
+2020-03-28 04:00:00,2.95,0.0,-0.0,0.0,2.07,92.15
+2020-03-28 05:00:00,2.17,14.0,42.2,12.0,2.21,92.15
+2020-03-28 06:00:00,3.02,158.0,429.05,68.0,2.0,92.15
+2020-03-28 07:00:00,7.09,339.0,709.19,83.0,1.72,85.75
+2020-03-28 08:00:00,10.12,467.0,703.06,122.0,2.48,69.0
+2020-03-28 09:00:00,11.56,596.0,804.89,121.0,3.86,57.55
+2020-03-28 10:00:00,12.61,682.0,868.98,115.0,4.34,53.6
+2020-03-28 11:00:00,13.6,686.0,807.72,142.0,4.62,53.85
+2020-03-28 12:00:00,14.85,531.0,368.24,291.0,5.79,50.25
+2020-03-28 13:00:00,15.34,323.0,71.34,281.0,5.38,46.75
+2020-03-28 14:00:00,15.11,116.0,0.0,116.0,3.79,50.25
+2020-03-28 15:00:00,14.46,104.0,0.0,104.0,3.72,52.0
+2020-03-28 16:00:00,12.79,143.0,318.85,77.0,3.31,60.05
+2020-03-28 17:00:00,11.66,10.0,22.46,9.0,3.1,69.25
+2020-03-28 18:00:00,10.63,0.0,-0.0,0.0,3.59,69.1
+2020-03-28 19:00:00,10.51,0.0,-0.0,0.0,3.45,71.7
+2020-03-28 20:00:00,10.08,0.0,-0.0,0.0,3.79,69.0
+2020-03-28 21:00:00,9.89,0.0,-0.0,0.0,4.21,66.45
+2020-03-28 22:00:00,9.58,0.0,-0.0,0.0,3.93,74.2
+2020-03-28 23:00:00,9.37,0.0,-0.0,0.0,3.59,74.2
+2020-03-29 00:00:00,8.83,0.0,-0.0,0.0,3.38,79.85
+2020-03-29 01:00:00,8.48,0.0,-0.0,0.0,3.17,82.75
+2020-03-29 02:00:00,7.99,0.0,-0.0,0.0,2.97,82.7
+2020-03-29 03:00:00,7.46,0.0,-0.0,0.0,2.76,85.8
+2020-03-29 04:00:00,7.49,0.0,-0.0,0.0,3.31,82.65
+2020-03-29 05:00:00,7.93,14.0,18.68,13.0,4.48,76.8
+2020-03-29 06:00:00,7.8,176.0,537.51,60.0,5.59,73.95
+2020-03-29 07:00:00,7.57,294.0,422.5,139.0,5.38,76.7
+2020-03-29 08:00:00,8.18,484.0,747.36,113.0,6.28,68.7
+2020-03-29 09:00:00,8.99,353.0,102.41,292.0,5.86,66.25
+2020-03-29 10:00:00,9.78,677.0,830.13,131.0,5.79,64.0
+2020-03-29 11:00:00,10.23,639.0,613.11,223.0,5.59,64.1
+2020-03-29 12:00:00,10.51,530.0,353.37,298.0,5.45,64.1
+2020-03-29 13:00:00,10.55,352.0,102.81,291.0,5.24,64.1
+2020-03-29 14:00:00,10.62,467.0,681.33,131.0,5.1,64.1
+2020-03-29 15:00:00,10.53,337.0,688.94,87.0,4.97,61.75
+2020-03-29 16:00:00,10.26,161.0,435.28,69.0,4.55,59.5
+2020-03-29 17:00:00,9.51,16.0,61.31,13.0,3.93,59.25
+2020-03-29 18:00:00,8.54,0.0,-0.0,0.0,3.38,63.7
+2020-03-29 19:00:00,7.91,0.0,-0.0,0.0,3.24,54.55
+2020-03-29 20:00:00,7.32,0.0,-0.0,0.0,3.52,56.55
+2020-03-29 21:00:00,6.78,0.0,-0.0,0.0,3.59,65.85
+2020-03-29 22:00:00,6.33,0.0,-0.0,0.0,3.38,70.95
+2020-03-29 23:00:00,5.82,0.0,-0.0,0.0,2.9,76.5
+2020-03-30 00:00:00,5.22,0.0,-0.0,0.0,2.55,79.35
+2020-03-30 01:00:00,4.88,0.0,-0.0,0.0,2.34,85.55
+2020-03-30 02:00:00,4.57,0.0,-0.0,0.0,2.41,88.8
+2020-03-30 03:00:00,4.63,0.0,-0.0,0.0,2.28,88.8
+2020-03-30 04:00:00,4.83,0.0,-0.0,0.0,2.48,82.35
+2020-03-30 05:00:00,5.02,4.0,0.0,4.0,2.69,82.35
+2020-03-30 06:00:00,5.81,37.0,0.0,37.0,2.76,82.5
+2020-03-30 07:00:00,7.28,65.0,0.0,65.0,3.17,76.7
+2020-03-30 08:00:00,8.06,246.0,47.8,222.0,3.45,82.7
+2020-03-30 09:00:00,9.62,374.0,131.44,295.0,3.52,79.9
+2020-03-30 10:00:00,11.58,351.0,58.83,312.0,4.34,71.85
+2020-03-30 11:00:00,12.43,385.0,79.01,331.0,4.83,64.55
+2020-03-30 12:00:00,12.42,319.0,34.78,296.0,4.48,66.95
+2020-03-30 13:00:00,12.6,201.0,1.67,200.0,4.69,66.95
+2020-03-30 14:00:00,12.26,76.0,0.0,76.0,4.76,64.55
+2020-03-30 15:00:00,11.57,144.0,16.34,138.0,3.45,71.85
+2020-03-30 16:00:00,11.15,77.0,18.54,73.0,3.38,74.45
+2020-03-30 17:00:00,10.34,12.0,18.75,11.0,2.9,77.15
+2020-03-30 18:00:00,9.65,0.0,-0.0,0.0,2.55,79.9
+2020-03-30 19:00:00,8.07,0.0,-0.0,0.0,2.28,89.05
+2020-03-30 20:00:00,7.19,0.0,-0.0,0.0,2.34,89.0
+2020-03-30 21:00:00,6.55,0.0,-0.0,0.0,2.34,92.3
+2020-03-30 22:00:00,5.96,0.0,-0.0,0.0,2.34,92.3
+2020-03-30 23:00:00,5.51,0.0,-0.0,0.0,2.28,92.25
+2020-03-31 00:00:00,5.85,0.0,-0.0,0.0,1.93,92.3
+2020-03-31 01:00:00,5.82,0.0,-0.0,0.0,1.72,92.3
+2020-03-31 02:00:00,5.57,0.0,-0.0,0.0,1.59,92.25
+2020-03-31 03:00:00,5.41,0.0,-0.0,0.0,1.38,95.75
+2020-03-31 04:00:00,5.21,0.0,-0.0,0.0,1.31,95.75
+2020-03-31 05:00:00,5.2,5.0,0.0,5.0,1.1,95.75
+2020-03-31 06:00:00,5.64,37.0,0.0,37.0,0.62,99.4
+2020-03-31 07:00:00,7.3,157.0,23.78,148.0,0.21,95.8
+2020-03-31 08:00:00,8.12,119.0,0.0,119.0,0.55,92.4
+2020-03-31 09:00:00,8.46,101.0,0.0,101.0,1.17,89.1
+2020-03-31 10:00:00,9.32,130.0,0.0,130.0,1.72,79.9
+2020-03-31 11:00:00,10.02,202.0,0.0,202.0,1.72,79.95
+2020-03-31 12:00:00,9.97,109.0,0.0,109.0,1.66,82.95
+2020-03-31 13:00:00,9.91,137.0,0.0,137.0,1.72,82.95
+2020-03-31 14:00:00,9.67,89.0,0.0,89.0,1.66,89.15
+2020-03-31 15:00:00,9.6,39.0,0.0,39.0,2.34,89.15
+2020-03-31 16:00:00,6.32,86.0,27.27,80.0,2.88,96.41
+2020-03-31 17:00:00,6.69,12.0,0.0,12.0,3.0,95.89
+2020-03-31 18:00:00,7.05,0.0,-0.0,0.0,3.11,95.38
+2020-03-31 19:00:00,7.41,0.0,-0.0,0.0,3.23,94.86
+2020-03-31 20:00:00,7.78,0.0,-0.0,0.0,3.35,94.35
+2020-03-31 21:00:00,8.14,0.0,-0.0,0.0,3.47,93.83
+2020-03-31 22:00:00,8.5,0.0,-0.0,0.0,3.58,93.32
+2020-03-31 23:00:00,8.86,0.0,-0.0,0.0,3.7,92.8
+2020-04-01 00:00:00,9.23,0.0,-0.0,0.0,3.82,92.29
+2020-04-01 01:00:00,9.59,0.0,-0.0,0.0,3.93,91.77
+2020-04-01 02:00:00,9.95,0.0,-0.0,0.0,4.05,91.26
+2020-04-01 03:00:00,10.32,0.0,-0.0,0.0,4.17,90.75
+2020-04-01 04:00:00,10.68,0.0,-0.0,0.0,4.29,90.23
+2020-04-01 05:00:00,11.04,30.0,167.29,19.0,4.4,89.72
+2020-04-01 06:00:00,11.41,60.0,0.0,60.0,4.52,89.2
+2020-04-01 07:00:00,11.77,329.0,567.97,114.0,4.64,88.69
+2020-04-01 08:00:00,12.74,442.0,520.01,178.0,5.03,86.25
+2020-04-01 09:00:00,13.15,473.0,326.5,275.0,5.79,80.35
+2020-04-01 10:00:00,14.14,408.0,115.26,331.0,5.66,69.75
+2020-04-01 11:00:00,14.93,445.0,145.27,345.0,6.07,60.5
+2020-04-01 12:00:00,15.21,389.0,94.6,326.0,5.59,60.5
+2020-04-01 13:00:00,15.43,491.0,386.79,258.0,5.38,58.45
+2020-04-01 14:00:00,15.16,361.0,258.97,231.0,4.55,60.5
+2020-04-01 15:00:00,14.95,244.0,207.24,167.0,3.17,62.75
+2020-04-01 16:00:00,14.81,155.0,331.79,82.0,2.69,64.95
+2020-04-01 17:00:00,13.94,9.0,0.0,9.0,2.0,67.25
+2020-04-01 18:00:00,12.67,0.0,-0.0,0.0,1.93,72.05
+2020-04-01 19:00:00,12.22,0.0,-0.0,0.0,2.14,74.6
+2020-04-01 20:00:00,11.57,0.0,-0.0,0.0,2.28,77.3
+2020-04-01 21:00:00,11.16,0.0,-0.0,0.0,2.21,83.05
+2020-04-01 22:00:00,10.87,0.0,-0.0,0.0,2.07,86.1
+2020-04-01 23:00:00,11.02,0.0,-0.0,0.0,1.86,89.3
+2020-04-02 00:00:00,10.52,0.0,-0.0,0.0,1.72,92.5
+2020-04-02 01:00:00,9.92,0.0,-0.0,0.0,1.66,95.9
+2020-04-02 02:00:00,9.15,0.0,-0.0,0.0,1.72,99.4
+2020-04-02 03:00:00,8.61,0.0,-0.0,0.0,1.72,99.4
+2020-04-02 04:00:00,8.24,0.0,-0.0,0.0,1.79,99.4
+2020-04-02 05:00:00,7.95,16.0,0.0,16.0,1.72,99.4
+2020-04-02 06:00:00,9.77,139.0,183.95,96.0,1.03,95.85
+2020-04-02 07:00:00,12.73,238.0,166.53,174.0,0.9,89.4
+2020-04-02 08:00:00,15.17,446.0,529.96,174.0,0.83,75.1
+2020-04-02 09:00:00,16.66,530.0,495.29,227.0,0.97,65.35
+2020-04-02 10:00:00,17.88,531.0,341.68,301.0,1.1,63.2
+2020-04-02 11:00:00,18.4,511.0,259.65,331.0,0.76,58.9
+2020-04-02 12:00:00,18.62,584.0,493.57,253.0,0.55,56.95
+2020-04-02 13:00:00,18.71,528.0,504.22,222.0,1.17,59.05
+2020-04-02 14:00:00,18.8,431.0,495.72,180.0,1.93,59.05
+2020-04-02 15:00:00,18.68,309.0,484.23,127.0,2.28,59.05
+2020-04-02 16:00:00,18.22,162.0,378.93,77.0,2.21,63.3
+2020-04-02 17:00:00,16.82,25.0,112.81,18.0,2.41,67.75
+2020-04-02 18:00:00,14.96,0.0,-0.0,0.0,2.62,72.45
+2020-04-02 19:00:00,14.43,0.0,-0.0,0.0,2.76,75.0
+2020-04-02 20:00:00,13.46,0.0,-0.0,0.0,2.83,77.6
+2020-04-02 21:00:00,12.69,0.0,-0.0,0.0,2.83,83.25
+2020-04-02 22:00:00,12.11,0.0,-0.0,0.0,2.9,83.15
+2020-04-02 23:00:00,11.78,0.0,-0.0,0.0,3.03,86.15
+2020-04-03 00:00:00,11.43,0.0,-0.0,0.0,2.97,86.15
+2020-04-03 01:00:00,11.1,0.0,-0.0,0.0,2.97,86.1
+2020-04-03 02:00:00,10.73,0.0,-0.0,0.0,3.03,89.25
+2020-04-03 03:00:00,10.36,0.0,-0.0,0.0,3.03,89.25
+2020-04-03 04:00:00,10.04,0.0,-0.0,0.0,2.97,92.5
+2020-04-03 05:00:00,9.61,38.0,166.96,25.0,2.9,92.45
+2020-04-03 06:00:00,10.49,188.0,467.32,76.0,2.83,89.25
+2020-04-03 07:00:00,12.83,345.0,599.92,111.0,2.62,86.25
+2020-04-03 08:00:00,15.5,489.0,684.31,134.0,2.83,72.55
+2020-04-03 09:00:00,17.57,596.0,706.59,160.0,2.9,65.45
+2020-04-03 10:00:00,19.17,660.0,706.29,181.0,2.9,59.15
+2020-04-03 11:00:00,20.23,555.0,336.66,320.0,2.97,55.3
+2020-04-03 12:00:00,20.94,619.0,571.66,233.0,3.17,53.5
+2020-04-03 13:00:00,21.38,571.0,631.43,185.0,3.17,49.95
+2020-04-03 14:00:00,21.43,455.0,563.98,167.0,3.1,49.95
+2020-04-03 15:00:00,21.22,304.0,426.19,142.0,2.9,49.95
+2020-04-03 16:00:00,20.46,174.0,437.47,74.0,2.21,55.45
+2020-04-03 17:00:00,18.66,33.0,195.8,20.0,2.41,63.4
+2020-04-03 18:00:00,16.75,0.0,-0.0,0.0,2.69,65.35
+2020-04-03 19:00:00,16.68,0.0,-0.0,0.0,2.69,63.05
+2020-04-03 20:00:00,15.75,0.0,-0.0,0.0,2.9,65.15
+2020-04-03 21:00:00,15.14,0.0,-0.0,0.0,2.97,67.45
+2020-04-03 22:00:00,14.64,0.0,-0.0,0.0,3.1,69.85
+2020-04-03 23:00:00,14.09,0.0,-0.0,0.0,2.97,72.3
+2020-04-04 00:00:00,12.81,0.0,-0.0,0.0,2.21,80.3
+2020-04-04 01:00:00,11.45,0.0,-0.0,0.0,1.93,86.15
+2020-04-04 02:00:00,11.22,0.0,-0.0,0.0,1.93,92.55
+2020-04-04 03:00:00,11.06,0.0,-0.0,0.0,2.28,95.9
+2020-04-04 04:00:00,10.65,0.0,-0.0,0.0,2.34,99.4
+2020-04-04 05:00:00,10.25,36.0,107.31,27.0,1.93,100.0
+2020-04-04 06:00:00,9.64,17.0,0.0,17.0,1.72,100.0
+2020-04-04 07:00:00,9.84,53.0,0.0,53.0,2.41,100.0
+2020-04-04 08:00:00,9.43,68.0,0.0,68.0,2.41,99.4
+2020-04-04 09:00:00,8.98,97.0,0.0,97.0,2.69,99.4
+2020-04-04 10:00:00,8.98,116.0,0.0,116.0,3.86,92.45
+2020-04-04 11:00:00,8.49,63.0,0.0,63.0,3.79,92.4
+2020-04-04 12:00:00,8.55,121.0,0.0,121.0,4.69,95.85
+2020-04-04 13:00:00,8.92,535.0,500.24,227.0,4.0,85.95
+2020-04-04 14:00:00,9.96,464.0,600.07,155.0,4.48,69.0
+2020-04-04 15:00:00,10.99,160.0,23.42,151.0,4.14,61.85
+2020-04-04 16:00:00,11.34,68.0,4.29,67.0,3.38,61.85
+2020-04-04 17:00:00,10.94,33.0,155.54,22.0,2.21,64.25
+2020-04-04 18:00:00,9.94,0.0,-0.0,0.0,2.21,66.45
+2020-04-04 19:00:00,9.19,0.0,-0.0,0.0,2.41,68.8
+2020-04-04 20:00:00,8.66,0.0,-0.0,0.0,2.69,74.05
+2020-04-04 21:00:00,7.9,0.0,-0.0,0.0,2.76,76.8
+2020-04-04 22:00:00,7.31,0.0,-0.0,0.0,2.69,85.75
+2020-04-04 23:00:00,7.01,0.0,-0.0,0.0,2.76,89.0
+2020-04-05 00:00:00,6.45,0.0,-0.0,0.0,2.55,92.3
+2020-04-05 01:00:00,6.53,0.0,-0.0,0.0,2.34,92.3
+2020-04-05 02:00:00,5.99,0.0,-0.0,0.0,2.34,88.95
+2020-04-05 03:00:00,5.68,0.0,-0.0,0.0,2.48,92.3
+2020-04-05 04:00:00,5.45,0.0,-0.0,0.0,2.28,88.9
+2020-04-05 05:00:00,5.06,44.0,144.69,31.0,2.07,88.85
+2020-04-05 06:00:00,6.0,185.0,365.99,93.0,1.86,88.95
+2020-04-05 07:00:00,8.87,353.0,578.0,121.0,2.0,82.85
+2020-04-05 08:00:00,10.64,510.0,719.33,129.0,2.62,77.15
+2020-04-05 09:00:00,12.03,549.0,494.06,239.0,3.24,62.1
+2020-04-05 10:00:00,13.01,605.0,489.75,268.0,4.34,53.7
+2020-04-05 11:00:00,13.37,622.0,483.4,280.0,4.28,50.0
+2020-04-05 12:00:00,13.63,551.0,353.66,309.0,3.52,48.15
+2020-04-05 13:00:00,14.32,461.0,269.33,294.0,3.59,44.75
+2020-04-05 14:00:00,14.41,338.0,171.42,249.0,3.52,43.25
+2020-04-05 15:00:00,14.09,166.0,28.31,155.0,3.24,44.75
+2020-04-05 16:00:00,13.62,117.0,80.15,98.0,2.62,48.15
+2020-04-05 17:00:00,12.62,30.0,79.97,24.0,2.14,51.65
+2020-04-05 18:00:00,11.43,0.0,-0.0,0.0,1.93,55.4
+2020-04-05 19:00:00,11.16,0.0,-0.0,0.0,1.79,61.85
+2020-04-05 20:00:00,10.71,0.0,-0.0,0.0,1.93,64.1
+2020-04-05 21:00:00,10.02,0.0,-0.0,0.0,2.0,66.45
+2020-04-05 22:00:00,9.45,0.0,-0.0,0.0,2.0,68.9
+2020-04-05 23:00:00,9.88,0.0,-0.0,0.0,2.76,66.45
+2020-04-06 00:00:00,10.2,0.0,-0.0,0.0,3.24,66.45
+2020-04-06 01:00:00,9.78,0.0,-0.0,0.0,3.24,66.35
+2020-04-06 02:00:00,9.54,0.0,-0.0,0.0,3.17,66.35
+2020-04-06 03:00:00,9.1,0.0,-0.0,0.0,3.1,71.4
+2020-04-06 04:00:00,9.16,0.0,-0.0,0.0,3.1,74.15
+2020-04-06 05:00:00,9.2,17.0,0.0,17.0,3.1,76.95
+2020-04-06 06:00:00,9.66,61.0,0.0,61.0,3.24,77.0
+2020-04-06 07:00:00,10.42,212.0,78.63,180.0,2.9,80.05
+2020-04-06 08:00:00,11.65,111.0,0.0,111.0,4.0,77.3
+2020-04-06 09:00:00,12.14,482.0,313.01,284.0,4.14,77.35
+2020-04-06 10:00:00,12.68,371.0,64.94,326.0,4.62,77.45
+2020-04-06 11:00:00,13.42,589.0,408.63,298.0,4.9,74.85
+2020-04-06 12:00:00,14.23,347.0,47.91,314.0,4.9,74.95
+2020-04-06 13:00:00,14.94,371.0,112.12,301.0,4.97,72.45
+2020-04-06 14:00:00,15.8,236.0,32.48,219.0,5.03,70.0
+2020-04-06 15:00:00,16.27,0.0,0.0,0.0,4.83,67.65
+2020-04-06 16:00:00,16.05,0.0,0.0,0.0,4.41,67.65
+2020-04-06 17:00:00,15.54,26.0,37.82,23.0,4.0,70.0
+2020-04-06 18:00:00,14.91,0.0,-0.0,0.0,3.93,72.45
+2020-04-06 19:00:00,13.99,0.0,-0.0,0.0,3.38,77.65
+2020-04-06 20:00:00,13.41,0.0,-0.0,0.0,3.52,80.4
+2020-04-06 21:00:00,13.2,0.0,-0.0,0.0,3.24,83.25
+2020-04-06 22:00:00,12.81,0.0,-0.0,0.0,2.97,86.25
+2020-04-06 23:00:00,12.46,0.0,-0.0,0.0,2.83,86.25
+2020-04-07 00:00:00,12.5,0.0,-0.0,0.0,2.9,86.25
+2020-04-07 01:00:00,12.65,0.0,-0.0,0.0,3.1,89.4
+2020-04-07 02:00:00,12.65,0.0,-0.0,0.0,3.24,89.4
+2020-04-07 03:00:00,12.54,0.0,-0.0,0.0,3.17,89.4
+2020-04-07 04:00:00,12.44,0.0,-0.0,0.0,3.24,89.4
+2020-04-07 05:00:00,12.6,60.0,255.71,34.0,3.72,89.4
+2020-04-07 06:00:00,13.76,218.0,543.94,75.0,4.14,83.35
+2020-04-07 07:00:00,15.9,377.0,664.22,103.0,3.79,75.15
+2020-04-07 08:00:00,17.73,506.0,679.21,139.0,4.97,70.3
+2020-04-07 09:00:00,19.11,614.0,715.13,158.0,5.79,63.5
+2020-04-07 10:00:00,19.95,528.0,289.48,326.0,6.48,59.35
+2020-04-07 11:00:00,20.49,616.0,463.21,284.0,6.97,55.45
+2020-04-07 12:00:00,20.5,549.0,344.81,310.0,7.52,49.8
+2020-04-07 13:00:00,20.1,572.0,588.61,202.0,7.72,46.2
+2020-04-07 14:00:00,19.32,274.0,64.45,240.0,7.52,47.65
+2020-04-07 15:00:00,17.9,155.0,15.12,149.0,6.14,52.75
+2020-04-07 16:00:00,16.3,66.0,0.0,66.0,6.28,56.5
+2020-04-07 17:00:00,14.8,23.0,11.96,22.0,6.21,64.95
+2020-04-07 18:00:00,13.32,0.0,-0.0,0.0,6.28,74.75
+2020-04-07 19:00:00,11.56,0.0,-0.0,0.0,6.48,69.25
+2020-04-07 20:00:00,10.48,0.0,-0.0,0.0,6.07,64.1
+2020-04-07 21:00:00,9.58,0.0,-0.0,0.0,6.41,59.25
+2020-04-07 22:00:00,8.52,0.0,-0.0,0.0,5.66,56.8
+2020-04-07 23:00:00,7.83,0.0,-0.0,0.0,5.45,56.7
+2020-04-08 00:00:00,7.15,0.0,-0.0,0.0,5.45,61.0
+2020-04-08 01:00:00,6.42,0.0,-0.0,0.0,5.38,63.25
+2020-04-08 02:00:00,5.91,0.0,-0.0,0.0,5.31,63.25
+2020-04-08 03:00:00,5.56,0.0,-0.0,0.0,5.24,65.65
+2020-04-08 04:00:00,5.23,0.0,-0.0,0.0,5.17,68.1
+2020-04-08 05:00:00,5.04,44.0,74.4,36.0,5.1,68.1
+2020-04-08 06:00:00,5.48,81.0,3.72,80.0,4.48,68.2
+2020-04-08 07:00:00,6.51,247.0,129.19,193.0,5.59,68.3
+2020-04-08 08:00:00,7.81,272.0,49.49,245.0,6.0,63.5
+2020-04-08 09:00:00,8.76,224.0,3.11,222.0,6.14,61.3
+2020-04-08 10:00:00,9.51,222.0,0.0,222.0,6.21,57.05
+2020-04-08 11:00:00,10.17,197.0,0.0,197.0,6.0,55.05
+2020-04-08 12:00:00,11.5,387.0,73.12,336.0,6.34,53.35
+2020-04-08 13:00:00,12.96,377.0,107.46,309.0,6.83,53.7
+2020-04-08 14:00:00,13.63,478.0,581.19,169.0,7.17,53.85
+2020-04-08 15:00:00,14.1,351.0,578.62,119.0,7.59,53.95
+2020-04-08 16:00:00,13.85,136.0,124.21,105.0,7.31,58.0
+2020-04-08 17:00:00,13.2,20.0,0.0,20.0,7.17,60.05
+2020-04-08 18:00:00,12.84,0.0,-0.0,0.0,7.45,62.2
+2020-04-08 19:00:00,12.65,0.0,-0.0,0.0,7.93,62.2
+2020-04-08 20:00:00,12.31,0.0,-0.0,0.0,8.07,64.45
+2020-04-08 21:00:00,10.96,0.0,-0.0,0.0,7.59,69.15
+2020-04-08 22:00:00,9.48,0.0,-0.0,0.0,7.31,68.9
+2020-04-08 23:00:00,8.1,0.0,-0.0,0.0,6.76,68.6
+2020-04-09 00:00:00,7.15,0.0,-0.0,0.0,6.28,71.05
+2020-04-09 01:00:00,6.39,0.0,-0.0,0.0,5.86,70.95
+2020-04-09 02:00:00,5.84,0.0,-0.0,0.0,5.59,68.3
+2020-04-09 03:00:00,5.41,0.0,-0.0,0.0,5.31,70.85
+2020-04-09 04:00:00,5.05,0.0,-0.0,0.0,5.1,73.55
+2020-04-09 05:00:00,4.75,34.0,17.65,32.0,4.9,76.3
+2020-04-09 06:00:00,5.15,108.0,21.88,102.0,5.72,73.55
+2020-04-09 07:00:00,5.71,197.0,40.15,180.0,5.45,76.5
+2020-04-09 08:00:00,6.27,294.0,65.36,258.0,5.31,76.55
+2020-04-09 09:00:00,6.93,435.0,172.95,323.0,5.31,73.8
+2020-04-09 10:00:00,7.73,461.0,145.63,358.0,5.45,71.15
+2020-04-09 11:00:00,8.55,696.0,637.96,233.0,5.45,68.7
+2020-04-09 12:00:00,9.41,600.0,428.91,299.0,5.45,63.9
+2020-04-09 13:00:00,10.0,434.0,183.68,317.0,5.45,59.35
+2020-04-09 14:00:00,10.32,0.0,0.0,0.0,5.38,57.15
+2020-04-09 15:00:00,10.58,349.0,523.43,137.0,5.1,53.1
+2020-04-09 16:00:00,10.52,191.0,390.23,92.0,4.83,53.1
+2020-04-09 17:00:00,10.13,53.0,260.65,29.0,3.66,55.05
+2020-04-09 18:00:00,9.04,0.0,-0.0,0.0,3.1,56.9
+2020-04-09 19:00:00,8.17,0.0,-0.0,0.0,2.76,61.2
+2020-04-09 20:00:00,7.17,0.0,-0.0,0.0,2.55,65.85
+2020-04-09 21:00:00,6.23,0.0,-0.0,0.0,2.34,68.3
+2020-04-09 22:00:00,5.3,0.0,-0.0,0.0,2.21,70.85
+2020-04-09 23:00:00,4.3,0.0,-0.0,0.0,2.14,73.45
+2020-04-10 00:00:00,3.34,0.0,-0.0,0.0,2.07,76.15
+2020-04-10 01:00:00,2.48,0.0,-0.0,0.0,2.07,82.15
+2020-04-10 02:00:00,1.71,0.0,-0.0,0.0,2.07,88.6
+2020-04-10 03:00:00,1.19,0.0,-0.0,0.0,2.14,88.55
+2020-04-10 04:00:00,0.86,0.0,-0.0,0.0,2.14,85.2
+2020-04-10 05:00:00,0.98,73.0,277.07,40.0,2.14,85.2
+2020-04-10 06:00:00,3.71,230.0,511.04,87.0,2.0,76.15
+2020-04-10 07:00:00,7.59,393.0,643.64,117.0,2.9,63.5
+2020-04-10 08:00:00,9.29,547.0,755.5,127.0,3.59,61.45
+2020-04-10 09:00:00,10.81,663.0,803.09,139.0,4.0,55.15
+2020-04-10 10:00:00,12.0,735.0,830.15,144.0,4.34,49.6
+2020-04-10 11:00:00,12.95,761.0,849.11,141.0,4.34,46.2
+2020-04-10 12:00:00,13.72,716.0,787.52,160.0,4.34,46.35
+2020-04-10 13:00:00,14.27,642.0,773.7,146.0,4.34,48.25
+2020-04-10 14:00:00,14.54,528.0,744.73,126.0,4.34,46.6
+2020-04-10 15:00:00,14.45,377.0,660.05,107.0,4.14,46.6
+2020-04-10 16:00:00,14.06,211.0,515.93,78.0,3.79,48.25
+2020-04-10 17:00:00,13.07,54.0,238.86,31.0,2.83,53.7
+2020-04-10 18:00:00,11.47,0.0,-0.0,0.0,2.34,57.55
+2020-04-10 19:00:00,10.5,0.0,-0.0,0.0,2.34,59.5
+2020-04-10 20:00:00,9.07,0.0,-0.0,0.0,2.14,66.25
+2020-04-10 21:00:00,7.58,0.0,-0.0,0.0,1.93,76.7
+2020-04-10 22:00:00,6.76,0.0,-0.0,0.0,1.72,79.5
+2020-04-10 23:00:00,6.05,0.0,-0.0,0.0,1.86,76.55
+2020-04-11 00:00:00,5.12,0.0,-0.0,0.0,2.0,79.35
+2020-04-11 01:00:00,4.23,0.0,-0.0,0.0,2.07,82.3
+2020-04-11 02:00:00,3.56,0.0,-0.0,0.0,1.93,85.45
+2020-04-11 03:00:00,3.22,0.0,-0.0,0.0,1.86,88.7
+2020-04-11 04:00:00,3.17,0.0,-0.0,0.0,1.86,88.7
+2020-04-11 05:00:00,3.4,48.0,48.07,42.0,1.79,85.45
+2020-04-11 06:00:00,6.27,156.0,115.64,123.0,1.38,82.55
+2020-04-11 07:00:00,11.01,328.0,334.0,183.0,1.31,69.15
+2020-04-11 08:00:00,13.2,419.0,292.34,255.0,1.79,57.9
+2020-04-11 09:00:00,14.53,531.0,371.21,287.0,2.0,48.4
+2020-04-11 10:00:00,15.74,649.0,547.1,257.0,1.93,45.15
+2020-04-11 11:00:00,16.63,638.0,465.6,296.0,2.14,42.15
+2020-04-11 12:00:00,17.44,609.0,449.17,290.0,2.41,42.3
+2020-04-11 13:00:00,18.0,526.0,385.96,277.0,2.69,42.45
+2020-04-11 14:00:00,18.16,379.0,226.19,256.0,2.97,42.45
+2020-04-11 15:00:00,18.1,265.0,183.99,189.0,2.97,42.45
+2020-04-11 16:00:00,17.38,149.0,137.48,113.0,2.0,50.75
+2020-04-11 17:00:00,16.03,34.0,29.85,31.0,1.93,52.5
+2020-04-11 18:00:00,14.61,0.0,-0.0,0.0,2.28,54.1
+2020-04-11 19:00:00,13.81,0.0,-0.0,0.0,2.48,55.9
+2020-04-11 20:00:00,12.73,0.0,-0.0,0.0,2.83,57.75
+2020-04-11 21:00:00,12.08,0.0,-0.0,0.0,3.1,59.85
+2020-04-11 22:00:00,11.85,0.0,-0.0,0.0,3.31,59.7
+2020-04-11 23:00:00,11.62,0.0,-0.0,0.0,3.31,59.7
+2020-04-12 00:00:00,11.24,0.0,-0.0,0.0,3.17,61.85
+2020-04-12 01:00:00,11.08,0.0,-0.0,0.0,3.1,61.85
+2020-04-12 02:00:00,11.11,0.0,-0.0,0.0,3.17,64.25
+2020-04-12 03:00:00,11.14,0.0,-0.0,0.0,3.66,66.65
+2020-04-12 04:00:00,10.86,0.0,-0.0,0.0,3.93,69.15
+2020-04-12 05:00:00,10.31,24.0,0.0,24.0,3.93,79.95
+2020-04-12 06:00:00,10.75,53.0,0.0,53.0,3.52,80.05
+2020-04-12 07:00:00,11.94,127.0,0.0,127.0,4.83,71.95
+2020-04-12 08:00:00,11.31,122.0,0.0,122.0,5.66,77.2
+2020-04-12 09:00:00,9.86,107.0,0.0,107.0,5.24,82.95
+2020-04-12 10:00:00,9.37,138.0,0.0,138.0,5.24,82.9
+2020-04-12 11:00:00,10.75,151.0,0.0,151.0,4.97,83.0
+2020-04-12 12:00:00,9.54,625.0,475.96,285.0,6.55,74.2
+2020-04-12 13:00:00,9.54,196.0,0.0,196.0,6.0,77.0
+2020-04-12 14:00:00,10.12,330.0,120.49,264.0,6.28,66.45
+2020-04-12 15:00:00,10.07,313.0,323.72,178.0,6.83,55.05
+2020-04-12 16:00:00,9.83,182.0,274.54,109.0,6.62,50.85
+2020-04-12 17:00:00,9.17,51.0,133.77,37.0,6.0,46.95
+2020-04-12 18:00:00,8.2,0.0,-0.0,0.0,5.66,48.55
+2020-04-12 19:00:00,7.17,0.0,-0.0,0.0,5.59,52.2
+2020-04-12 20:00:00,6.45,0.0,-0.0,0.0,5.31,54.15
+2020-04-12 21:00:00,6.0,0.0,-0.0,0.0,5.38,54.15
+2020-04-12 22:00:00,5.48,0.0,-0.0,0.0,5.52,58.45
+2020-04-12 23:00:00,5.12,0.0,-0.0,0.0,5.59,60.65
+2020-04-13 00:00:00,4.87,0.0,-0.0,0.0,5.66,63.05
+2020-04-13 01:00:00,4.51,0.0,-0.0,0.0,5.72,65.4
+2020-04-13 02:00:00,4.38,0.0,-0.0,0.0,5.86,65.4
+2020-04-13 03:00:00,4.11,0.0,-0.0,0.0,5.93,70.6
+2020-04-13 04:00:00,3.63,0.0,-0.0,0.0,6.0,76.15
+2020-04-13 05:00:00,3.47,33.0,0.0,33.0,5.86,76.15
+2020-04-13 06:00:00,3.63,45.0,0.0,45.0,6.0,79.15
+2020-04-13 07:00:00,4.02,81.0,0.0,81.0,5.66,85.5
+2020-04-13 08:00:00,4.23,129.0,0.0,129.0,4.48,95.75
+2020-04-13 09:00:00,4.82,170.0,0.0,170.0,4.48,95.75
+2020-04-13 10:00:00,4.7,152.0,0.0,152.0,4.34,99.4
+2020-04-13 11:00:00,3.78,148.0,0.0,148.0,7.24,92.2
+2020-04-13 12:00:00,3.97,101.0,0.0,101.0,6.9,88.8
+2020-04-13 13:00:00,4.46,127.0,0.0,127.0,6.62,88.85
+2020-04-13 14:00:00,4.7,179.0,1.81,178.0,6.76,92.25
+2020-04-13 15:00:00,4.68,112.0,0.0,112.0,6.0,92.25
+2020-04-13 16:00:00,4.77,39.0,0.0,39.0,5.59,95.75
+2020-04-13 17:00:00,4.84,33.0,18.38,31.0,5.17,92.25
+2020-04-13 18:00:00,4.83,0.0,-0.0,0.0,4.76,92.25
+2020-04-13 19:00:00,4.64,0.0,-0.0,0.0,4.07,92.25
+2020-04-13 20:00:00,4.74,0.0,-0.0,0.0,4.0,92.25
+2020-04-13 21:00:00,4.87,0.0,-0.0,0.0,4.28,92.25
+2020-04-13 22:00:00,4.87,0.0,-0.0,0.0,4.62,88.85
+2020-04-13 23:00:00,4.58,0.0,-0.0,0.0,4.83,92.25
+2020-04-14 00:00:00,4.19,0.0,-0.0,0.0,4.76,92.2
+2020-04-14 01:00:00,3.63,0.0,-0.0,0.0,4.41,95.7
+2020-04-14 02:00:00,3.36,0.0,-0.0,0.0,3.52,95.7
+2020-04-14 03:00:00,3.29,0.0,-0.0,0.0,3.31,95.7
+2020-04-14 04:00:00,3.27,0.0,-0.0,0.0,3.93,99.4
+2020-04-14 05:00:00,3.42,26.0,0.0,26.0,4.0,92.15
+2020-04-14 06:00:00,3.55,43.0,0.0,43.0,4.07,95.7
+2020-04-14 07:00:00,4.3,105.0,0.0,105.0,3.59,88.85
+2020-04-14 08:00:00,4.52,113.0,0.0,113.0,3.24,92.25
+2020-04-14 09:00:00,4.7,127.0,0.0,127.0,3.17,92.25
+2020-04-14 10:00:00,5.33,124.0,0.0,124.0,3.03,88.9
+2020-04-14 11:00:00,5.81,144.0,0.0,144.0,3.17,85.7
+2020-04-14 12:00:00,6.52,129.0,0.0,129.0,2.9,92.3
+2020-04-14 13:00:00,7.07,145.0,0.0,145.0,2.76,92.35
+2020-04-14 14:00:00,7.37,69.0,0.0,69.0,2.97,85.8
+2020-04-14 15:00:00,7.56,117.0,0.0,117.0,2.83,85.8
+2020-04-14 16:00:00,7.51,73.0,0.0,73.0,2.9,85.8
+2020-04-14 17:00:00,7.02,11.0,0.0,11.0,2.55,85.75
+2020-04-14 18:00:00,6.11,0.0,-0.0,0.0,2.28,85.7
+2020-04-14 19:00:00,4.91,0.0,-0.0,0.0,1.59,92.25
+2020-04-14 20:00:00,4.54,0.0,-0.0,0.0,1.59,92.25
+2020-04-14 21:00:00,4.56,0.0,-0.0,0.0,1.52,95.75
+2020-04-14 22:00:00,4.34,0.0,-0.0,0.0,1.52,92.25
+2020-04-14 23:00:00,4.15,0.0,-0.0,0.0,1.45,95.75
+2020-04-15 00:00:00,3.97,0.0,-0.0,0.0,1.45,95.75
+2020-04-15 01:00:00,3.88,0.0,-0.0,0.0,1.45,95.75
+2020-04-15 02:00:00,3.87,0.0,-0.0,0.0,1.45,95.75
+2020-04-15 03:00:00,3.81,0.0,-0.0,0.0,1.31,95.75
+2020-04-15 04:00:00,3.82,0.0,-0.0,0.0,1.17,95.75
+2020-04-15 05:00:00,3.8,26.0,0.0,26.0,1.1,95.75
+2020-04-15 06:00:00,3.92,60.0,0.0,60.0,1.72,95.75
+2020-04-15 07:00:00,4.54,163.0,6.6,160.0,1.66,92.25
+2020-04-15 08:00:00,5.9,341.0,101.61,282.0,2.14,82.55
+2020-04-15 09:00:00,6.94,327.0,35.51,303.0,2.41,76.65
+2020-04-15 10:00:00,7.95,158.0,0.0,158.0,2.48,71.25
+2020-04-15 11:00:00,8.91,263.0,2.66,261.0,2.69,71.4
+2020-04-15 12:00:00,9.73,546.0,264.31,354.0,2.9,71.5
+2020-04-15 13:00:00,10.06,122.0,0.0,122.0,3.17,71.6
+2020-04-15 14:00:00,9.73,117.0,0.0,117.0,3.31,68.9
+2020-04-15 15:00:00,9.59,174.0,18.66,166.0,3.17,66.35
+2020-04-15 16:00:00,9.49,80.0,3.6,79.0,2.48,66.35
+2020-04-15 17:00:00,8.95,38.0,17.09,36.0,1.79,68.8
+2020-04-15 18:00:00,8.02,0.0,-0.0,0.0,1.52,73.95
+2020-04-15 19:00:00,6.72,0.0,-0.0,0.0,1.52,85.7
+2020-04-15 20:00:00,5.98,0.0,-0.0,0.0,1.24,82.55
+2020-04-15 21:00:00,5.67,0.0,-0.0,0.0,1.17,82.5
+2020-04-15 22:00:00,5.59,0.0,-0.0,0.0,1.17,82.5
+2020-04-15 23:00:00,5.3,0.0,-0.0,0.0,1.24,79.4
+2020-04-16 00:00:00,4.98,0.0,-0.0,0.0,1.24,82.4
+2020-04-16 01:00:00,4.84,0.0,-0.0,0.0,1.31,82.4
+2020-04-16 02:00:00,4.41,0.0,-0.0,0.0,1.38,82.35
+2020-04-16 03:00:00,4.08,0.0,-0.0,0.0,1.38,85.5
+2020-04-16 04:00:00,3.49,0.0,-0.0,0.0,1.45,85.45
+2020-04-16 05:00:00,3.0,106.0,373.63,49.0,1.45,88.7
+2020-04-16 06:00:00,6.18,265.0,551.04,93.0,0.55,85.7
+2020-04-16 07:00:00,8.85,439.0,715.58,110.0,0.34,79.85
+2020-04-16 08:00:00,10.62,584.0,780.67,127.0,0.34,69.1
+2020-04-16 09:00:00,11.49,608.0,514.36,258.0,1.1,59.7
+2020-04-16 10:00:00,12.16,442.0,98.85,369.0,1.38,53.5
+2020-04-16 11:00:00,12.93,548.0,226.35,377.0,1.38,48.0
+2020-04-16 12:00:00,13.16,397.0,62.98,351.0,1.31,48.0
+2020-04-16 13:00:00,13.56,345.0,51.15,311.0,1.03,44.65
+2020-04-16 14:00:00,13.56,306.0,72.8,265.0,1.1,44.65
+2020-04-16 15:00:00,13.45,268.0,150.27,203.0,1.31,44.65
+2020-04-16 16:00:00,13.21,198.0,294.54,115.0,1.52,46.2
+2020-04-16 17:00:00,12.23,70.0,222.87,43.0,1.59,57.65
+2020-04-16 18:00:00,10.75,0.0,-0.0,0.0,1.79,61.75
+2020-04-16 19:00:00,9.68,0.0,-0.0,0.0,1.45,74.2
+2020-04-16 20:00:00,9.81,0.0,-0.0,0.0,1.1,63.9
+2020-04-16 21:00:00,10.77,0.0,-0.0,0.0,0.48,57.3
+2020-04-16 22:00:00,10.57,0.0,-0.0,0.0,0.28,55.15
+2020-04-16 23:00:00,10.3,0.0,-0.0,0.0,0.69,57.15
+2020-04-17 00:00:00,9.96,0.0,-0.0,0.0,0.9,57.15
+2020-04-17 01:00:00,8.84,0.0,-0.0,0.0,1.1,61.45
+2020-04-17 02:00:00,8.59,0.0,-0.0,0.0,1.03,63.7
+2020-04-17 03:00:00,8.25,0.0,-0.0,0.0,1.1,66.05
+2020-04-17 04:00:00,7.9,0.0,-0.0,0.0,1.1,66.05
+2020-04-17 05:00:00,7.49,30.0,0.0,30.0,1.17,71.15
+2020-04-17 06:00:00,8.82,77.0,0.0,77.0,0.62,74.05
+2020-04-17 07:00:00,10.94,192.0,19.37,183.0,0.34,71.75
+2020-04-17 08:00:00,12.17,286.0,38.98,263.0,0.62,64.45
+2020-04-17 09:00:00,12.84,399.0,91.99,336.0,1.1,59.95
+2020-04-17 10:00:00,13.58,663.0,504.94,288.0,1.31,53.85
+2020-04-17 11:00:00,13.88,447.0,92.17,377.0,1.38,50.1
+2020-04-17 12:00:00,13.86,215.0,0.0,215.0,1.38,50.0
+2020-04-17 13:00:00,14.09,405.0,112.19,330.0,1.24,48.25
+2020-04-17 14:00:00,14.02,394.0,213.43,273.0,1.17,46.5
+2020-04-17 15:00:00,13.98,217.0,55.0,193.0,1.03,46.5
+2020-04-17 16:00:00,13.57,155.0,108.51,124.0,0.48,51.9
+2020-04-17 17:00:00,13.41,75.0,255.57,43.0,0.14,51.9
+2020-04-17 18:00:00,13.07,0.0,-0.0,0.0,0.41,53.7
+2020-04-17 19:00:00,12.53,0.0,-0.0,0.0,0.34,47.85
+2020-04-17 20:00:00,12.38,0.0,-0.0,0.0,0.21,46.1
+2020-04-17 21:00:00,12.15,0.0,-0.0,0.0,0.69,45.95
+2020-04-17 22:00:00,11.45,0.0,-0.0,0.0,0.97,49.45
+2020-04-17 23:00:00,10.58,0.0,-0.0,0.0,1.03,55.15
+2020-04-18 00:00:00,9.32,0.0,-0.0,0.0,1.31,63.8
+2020-04-18 01:00:00,8.59,0.0,-0.0,0.0,1.45,68.7
+2020-04-18 02:00:00,7.8,0.0,-0.0,0.0,1.52,73.9
+2020-04-18 03:00:00,7.2,0.0,-0.0,0.0,1.52,73.8
+2020-04-18 04:00:00,6.85,0.0,0.0,0.0,1.45,73.8
+2020-04-18 05:00:00,6.95,115.0,379.83,53.0,1.38,76.65
+2020-04-18 06:00:00,9.23,280.0,589.34,90.0,0.55,76.95
+2020-04-18 07:00:00,11.98,445.0,702.8,115.0,0.21,59.85
+2020-04-18 08:00:00,13.66,592.0,773.53,132.0,0.41,50.0
+2020-04-18 09:00:00,14.89,705.0,818.29,141.0,1.17,48.4
+2020-04-18 10:00:00,15.74,779.0,854.31,141.0,1.79,41.9
+2020-04-18 11:00:00,16.17,251.0,1.31,250.0,1.79,40.5
+2020-04-18 12:00:00,16.49,668.0,528.45,278.0,1.79,39.15
+2020-04-18 13:00:00,16.45,391.0,92.23,329.0,1.93,40.6
+2020-04-18 14:00:00,16.41,398.0,215.54,275.0,2.07,40.6
+2020-04-18 15:00:00,16.08,385.0,547.57,144.0,2.0,43.65
+2020-04-18 16:00:00,15.3,239.0,518.01,89.0,1.72,54.25
+2020-04-18 17:00:00,14.51,81.0,294.0,43.0,1.72,56.15
+2020-04-18 18:00:00,13.18,0.0,-0.0,0.0,1.79,62.3
+2020-04-18 19:00:00,11.62,0.0,-0.0,0.0,1.93,69.25
+2020-04-18 20:00:00,9.83,0.0,-0.0,0.0,2.07,77.0
+2020-04-18 21:00:00,8.63,0.0,-0.0,0.0,2.14,79.75
+2020-04-18 22:00:00,7.68,0.0,-0.0,0.0,2.21,82.65
+2020-04-18 23:00:00,6.8,0.0,-0.0,0.0,2.28,82.55
+2020-04-19 00:00:00,6.19,0.0,-0.0,0.0,2.28,79.5
+2020-04-19 01:00:00,5.68,0.0,-0.0,0.0,2.28,82.5
+2020-04-19 02:00:00,5.11,0.0,-0.0,0.0,2.28,82.4
+2020-04-19 03:00:00,4.64,0.0,-0.0,0.0,2.21,82.35
+2020-04-19 04:00:00,4.12,0.0,0.0,0.0,2.21,85.5
+2020-04-19 05:00:00,4.46,116.0,338.34,59.0,1.93,85.55
+2020-04-19 06:00:00,7.94,281.0,565.03,96.0,1.38,85.85
+2020-04-19 07:00:00,12.75,449.0,695.71,119.0,1.24,69.45
+2020-04-19 08:00:00,14.99,594.0,766.01,135.0,1.45,54.25
+2020-04-19 09:00:00,16.35,711.0,821.89,141.0,1.72,48.8
+2020-04-19 10:00:00,17.33,785.0,856.34,142.0,2.14,45.45
+2020-04-19 11:00:00,17.99,801.0,851.02,148.0,2.28,42.45
+2020-04-19 12:00:00,18.78,761.0,815.63,156.0,2.55,41.05
+2020-04-19 13:00:00,19.11,689.0,813.7,139.0,2.62,38.2
+2020-04-19 14:00:00,19.24,568.0,764.39,129.0,2.69,38.2
+2020-04-19 15:00:00,19.0,414.0,675.91,114.0,2.83,38.2
+2020-04-19 16:00:00,18.37,245.0,535.08,88.0,2.76,44.05
+2020-04-19 17:00:00,16.76,83.0,277.64,46.0,2.55,52.65
+2020-04-19 18:00:00,14.76,0.0,-0.0,0.0,2.55,60.4
+2020-04-19 19:00:00,13.73,0.0,-0.0,0.0,2.41,62.45
+2020-04-19 20:00:00,12.21,0.0,-0.0,0.0,2.55,69.35
+2020-04-19 21:00:00,11.03,0.0,-0.0,0.0,2.41,74.45
+2020-04-19 22:00:00,9.99,0.0,-0.0,0.0,2.41,79.95
+2020-04-19 23:00:00,9.12,0.0,-0.0,0.0,2.34,82.85
+2020-04-20 00:00:00,8.18,0.0,-0.0,0.0,2.21,89.05
+2020-04-20 01:00:00,7.24,0.0,-0.0,0.0,2.14,92.35
+2020-04-20 02:00:00,6.45,0.0,-0.0,0.0,2.07,92.3
+2020-04-20 03:00:00,5.84,0.0,-0.0,0.0,2.07,88.95
+2020-04-20 04:00:00,5.39,0.0,0.0,0.0,2.14,88.9
+2020-04-20 05:00:00,5.86,117.0,322.51,61.0,1.93,88.95
+2020-04-20 06:00:00,9.55,277.0,517.5,105.0,1.52,85.95
+2020-04-20 07:00:00,13.84,447.0,678.43,122.0,1.31,72.2
+2020-04-20 08:00:00,16.05,594.0,758.7,136.0,1.17,60.75
+2020-04-20 09:00:00,17.56,710.0,814.05,142.0,0.83,56.75
+2020-04-20 10:00:00,18.58,787.0,859.76,138.0,0.97,51.15
+2020-04-20 11:00:00,19.28,812.0,877.93,135.0,1.1,49.45
+2020-04-20 12:00:00,19.81,776.0,855.86,138.0,1.24,47.8
+2020-04-20 13:00:00,20.31,695.0,827.01,133.0,1.17,44.6
+2020-04-20 14:00:00,20.56,582.0,808.04,115.0,1.1,41.55
+2020-04-20 15:00:00,20.37,423.0,706.08,107.0,1.24,43.0
+2020-04-20 16:00:00,19.9,256.0,585.4,82.0,1.52,46.1
+2020-04-20 17:00:00,18.6,89.0,327.85,44.0,1.66,56.95
+2020-04-20 18:00:00,16.36,0.0,-0.0,0.0,2.07,62.95
+2020-04-20 19:00:00,14.86,0.0,-0.0,0.0,1.52,72.4
+2020-04-20 20:00:00,12.58,0.0,-0.0,0.0,1.93,74.7
+2020-04-20 21:00:00,10.74,0.0,-0.0,0.0,2.07,83.0
+2020-04-20 22:00:00,9.49,0.0,-0.0,0.0,1.93,82.9
+2020-04-20 23:00:00,8.61,0.0,-0.0,0.0,1.86,85.9
+2020-04-21 00:00:00,7.72,0.0,-0.0,0.0,1.86,89.0
+2020-04-21 01:00:00,6.95,0.0,-0.0,0.0,1.86,89.0
+2020-04-21 02:00:00,6.4,0.0,-0.0,0.0,1.86,88.95
+2020-04-21 03:00:00,5.99,0.0,-0.0,0.0,1.79,85.7
+2020-04-21 04:00:00,5.76,0.0,0.0,0.0,1.72,88.9
+2020-04-21 05:00:00,6.88,125.0,358.07,61.0,1.38,85.75
+2020-04-21 06:00:00,11.39,292.0,581.17,96.0,0.55,77.3
+2020-04-21 07:00:00,15.46,455.0,686.4,123.0,0.28,62.85
+2020-04-21 08:00:00,17.64,599.0,753.23,141.0,0.48,52.75
+2020-04-21 09:00:00,18.97,718.0,820.64,142.0,1.24,47.65
+2020-04-21 10:00:00,19.99,795.0,865.85,138.0,1.72,43.0
+2020-04-21 11:00:00,20.58,807.0,849.15,149.0,1.79,40.1
+2020-04-21 12:00:00,20.92,762.0,798.31,164.0,2.0,40.1
+2020-04-21 13:00:00,20.87,664.0,701.18,185.0,2.28,40.1
+2020-04-21 14:00:00,20.81,567.0,739.43,137.0,2.21,40.1
+2020-04-21 15:00:00,20.7,420.0,675.98,115.0,2.14,40.1
+2020-04-21 16:00:00,20.03,257.0,571.4,85.0,2.34,44.6
+2020-04-21 17:00:00,18.27,95.0,354.04,45.0,2.41,52.9
+2020-04-21 18:00:00,16.5,0.0,-0.0,0.0,2.41,52.65
+2020-04-21 19:00:00,15.39,0.0,-0.0,0.0,2.34,50.5
+2020-04-21 20:00:00,13.47,0.0,-0.0,0.0,2.34,55.9
+2020-04-21 21:00:00,11.9,0.0,-0.0,0.0,2.41,62.1
+2020-04-21 22:00:00,10.72,0.0,-0.0,0.0,2.41,66.55
+2020-04-21 23:00:00,9.79,0.0,-0.0,0.0,2.34,71.5
+2020-04-22 00:00:00,9.09,0.0,-0.0,0.0,2.28,74.15
+2020-04-22 01:00:00,8.48,0.0,-0.0,0.0,2.14,76.85
+2020-04-22 02:00:00,7.95,0.0,-0.0,0.0,2.07,79.7
+2020-04-22 03:00:00,7.45,0.0,-0.0,0.0,1.93,82.65
+2020-04-22 04:00:00,6.99,0.0,0.0,0.0,1.86,82.6
+2020-04-22 05:00:00,7.69,137.0,429.9,58.0,1.59,85.8
+2020-04-22 06:00:00,11.45,296.0,581.78,97.0,1.1,80.15
+2020-04-22 07:00:00,16.13,458.0,686.14,123.0,0.9,65.25
+2020-04-22 08:00:00,18.29,605.0,764.25,137.0,1.1,58.9
+2020-04-22 09:00:00,19.88,721.0,818.74,143.0,1.38,55.2
+2020-04-22 10:00:00,21.2,794.0,852.28,144.0,1.79,49.95
+2020-04-22 11:00:00,22.08,804.0,836.13,153.0,2.14,40.5
+2020-04-22 12:00:00,22.54,769.0,811.78,158.0,2.34,36.4
+2020-04-22 13:00:00,22.75,693.0,798.07,145.0,2.62,35.1
+2020-04-22 14:00:00,22.74,579.0,770.85,128.0,2.83,35.1
+2020-04-22 15:00:00,22.48,427.0,692.59,112.0,2.97,35.1
+2020-04-22 16:00:00,21.89,263.0,587.33,84.0,2.55,40.35
+2020-04-22 17:00:00,20.22,101.0,378.88,46.0,2.14,47.9
+2020-04-22 18:00:00,18.04,0.0,-0.0,0.0,2.41,52.9
+2020-04-22 19:00:00,16.51,0.0,-0.0,0.0,2.34,56.6
+2020-04-22 20:00:00,14.7,0.0,-0.0,0.0,2.48,64.95
+2020-04-22 21:00:00,13.35,0.0,-0.0,0.0,2.48,72.1
+2020-04-22 22:00:00,12.24,0.0,-0.0,0.0,2.48,74.6
+2020-04-22 23:00:00,11.28,0.0,-0.0,0.0,2.48,77.2
+2020-04-23 00:00:00,10.36,0.0,-0.0,0.0,2.41,77.15
+2020-04-23 01:00:00,9.62,0.0,-0.0,0.0,2.34,79.9
+2020-04-23 02:00:00,9.08,0.0,-0.0,0.0,2.41,79.85
+2020-04-23 03:00:00,8.6,0.0,-0.0,0.0,2.34,82.75
+2020-04-23 04:00:00,8.18,3.0,0.0,3.0,2.28,82.7
+2020-04-23 05:00:00,8.76,145.0,471.6,56.0,2.0,82.75
+2020-04-23 06:00:00,12.2,310.0,631.52,91.0,1.52,80.2
+2020-04-23 07:00:00,16.26,470.0,716.43,117.0,1.93,62.95
+2020-04-23 08:00:00,18.11,612.0,773.6,135.0,2.28,56.85
+2020-04-23 09:00:00,19.71,727.0,828.22,139.0,2.76,53.25
+2020-04-23 10:00:00,21.04,766.0,754.13,188.0,3.52,46.5
+2020-04-23 11:00:00,21.51,802.0,820.74,160.0,4.07,40.35
+2020-04-23 12:00:00,21.71,701.0,584.51,259.0,4.34,40.35
+2020-04-23 13:00:00,21.78,688.0,769.41,157.0,4.69,40.35
+2020-04-23 14:00:00,21.61,572.0,737.39,138.0,4.9,38.9
+2020-04-23 15:00:00,20.89,425.0,674.09,116.0,4.69,41.55
+2020-04-23 16:00:00,20.25,260.0,554.31,89.0,4.21,44.6
+2020-04-23 17:00:00,19.16,97.0,308.56,51.0,4.0,45.95
+2020-04-23 18:00:00,17.55,0.0,-0.0,0.0,3.72,47.3
+2020-04-23 19:00:00,16.65,0.0,-0.0,0.0,3.66,43.8
+2020-04-23 20:00:00,15.61,0.0,-0.0,0.0,3.45,45.15
+2020-04-23 21:00:00,14.63,0.0,-0.0,0.0,3.31,44.9
+2020-04-23 22:00:00,13.68,0.0,-0.0,0.0,3.17,46.35
+2020-04-23 23:00:00,12.65,0.0,-0.0,0.0,2.9,49.7
+2020-04-24 00:00:00,11.53,0.0,-0.0,0.0,2.55,55.4
+2020-04-24 01:00:00,10.46,0.0,-0.0,0.0,2.41,61.75
+2020-04-24 02:00:00,9.54,0.0,-0.0,0.0,2.34,66.35
+2020-04-24 03:00:00,8.78,0.0,-0.0,0.0,2.41,74.05
+2020-04-24 04:00:00,8.11,2.0,0.0,2.0,2.34,76.8
+2020-04-24 05:00:00,8.3,152.0,490.71,57.0,2.21,79.7
+2020-04-24 06:00:00,10.48,314.0,623.16,95.0,2.34,71.7
+2020-04-24 07:00:00,12.72,477.0,720.14,119.0,2.83,66.95
+2020-04-24 08:00:00,14.52,619.0,776.48,137.0,3.03,60.4
+2020-04-24 09:00:00,16.16,731.0,818.06,147.0,3.38,54.45
+2020-04-24 10:00:00,17.47,807.0,863.44,142.0,3.79,47.3
+2020-04-24 11:00:00,18.35,818.0,845.02,154.0,3.86,42.45
+2020-04-24 12:00:00,18.87,777.0,805.63,165.0,3.66,39.55
+2020-04-24 13:00:00,19.14,702.0,795.89,150.0,3.72,36.8
+2020-04-24 14:00:00,19.14,568.0,692.54,158.0,3.79,35.45
+2020-04-24 15:00:00,18.8,431.0,675.42,119.0,3.93,35.35
+2020-04-24 16:00:00,18.31,269.0,579.79,88.0,3.79,36.55
+2020-04-24 17:00:00,17.33,109.0,398.78,48.0,3.03,40.6
+2020-04-24 18:00:00,15.67,0.0,-0.0,0.0,2.48,41.9
+2020-04-24 19:00:00,13.89,0.0,-0.0,0.0,1.93,50.1
+2020-04-24 20:00:00,12.33,0.0,-0.0,0.0,1.59,57.65
+2020-04-24 21:00:00,12.33,0.0,-0.0,0.0,1.38,51.5
+2020-04-24 22:00:00,13.22,0.0,-0.0,0.0,1.1,46.2
+2020-04-24 23:00:00,12.92,0.0,-0.0,0.0,0.69,44.5
+2020-04-25 00:00:00,12.38,0.0,-0.0,0.0,0.41,46.1
+2020-04-25 01:00:00,11.56,0.0,-0.0,0.0,0.69,49.45
+2020-04-25 02:00:00,10.79,0.0,-0.0,0.0,0.97,53.1
+2020-04-25 03:00:00,9.34,0.0,-0.0,0.0,1.24,57.05
+2020-04-25 04:00:00,8.21,4.0,0.0,4.0,1.31,66.05
+2020-04-25 05:00:00,8.62,87.0,55.44,76.0,1.03,66.15
+2020-04-25 06:00:00,9.77,299.0,528.08,111.0,1.03,74.2
+2020-04-25 07:00:00,10.68,372.0,299.13,222.0,2.28,80.05
+2020-04-25 08:00:00,11.82,325.0,57.62,289.0,3.52,74.55
+2020-04-25 09:00:00,12.12,339.0,30.65,317.0,3.72,69.35
+2020-04-25 10:00:00,12.55,136.0,0.0,136.0,3.66,69.45
+2020-04-25 11:00:00,12.35,231.0,0.0,231.0,3.24,71.95
+2020-04-25 12:00:00,13.04,113.0,0.0,113.0,3.1,69.55
+2020-04-25 13:00:00,13.74,257.0,4.3,254.0,3.24,67.15
+2020-04-25 14:00:00,13.98,153.0,0.0,153.0,3.31,64.85
+2020-04-25 15:00:00,14.23,125.0,0.0,125.0,3.72,62.55
+2020-04-25 16:00:00,14.14,160.0,79.15,135.0,3.45,60.3
+2020-04-25 17:00:00,13.75,100.0,280.57,56.0,2.69,62.45
+2020-04-25 18:00:00,12.9,0.0,-0.0,0.0,2.0,64.65
+2020-04-25 19:00:00,11.26,0.0,-0.0,0.0,1.52,74.45
+2020-04-25 20:00:00,9.89,0.0,-0.0,0.0,1.31,79.95
+2020-04-25 21:00:00,9.36,0.0,-0.0,0.0,1.31,79.9
+2020-04-25 22:00:00,8.74,0.0,-0.0,0.0,1.38,85.9
+2020-04-25 23:00:00,7.9,0.0,-0.0,0.0,1.45,85.85
+2020-04-26 00:00:00,8.59,0.0,-0.0,0.0,1.17,85.9
+2020-04-26 01:00:00,9.28,0.0,-0.0,0.0,0.76,82.85
+2020-04-26 02:00:00,9.11,0.0,-0.0,0.0,0.76,82.85
+2020-04-26 03:00:00,8.23,0.0,-0.0,0.0,1.1,89.05
+2020-04-26 04:00:00,7.82,2.0,0.0,2.0,1.1,85.85
+2020-04-26 05:00:00,7.53,46.0,0.0,46.0,0.97,89.0
+2020-04-26 06:00:00,9.63,143.0,19.42,136.0,0.69,89.15
+2020-04-26 07:00:00,10.94,312.0,144.35,239.0,1.1,86.1
+2020-04-26 08:00:00,11.98,212.0,3.18,210.0,1.72,83.15
+2020-04-26 09:00:00,12.84,316.0,19.4,302.0,2.0,86.25
+2020-04-26 10:00:00,13.87,346.0,20.58,330.0,2.48,80.4
+2020-04-26 11:00:00,14.41,170.0,0.0,170.0,2.97,77.75
+2020-04-26 12:00:00,13.12,193.0,0.0,193.0,3.72,77.5
+2020-04-26 13:00:00,12.25,200.0,0.0,200.0,2.9,86.2
+2020-04-26 14:00:00,12.6,340.0,91.85,285.0,3.79,77.45
+2020-04-26 15:00:00,13.14,374.0,407.32,183.0,2.62,74.75
+2020-04-26 16:00:00,13.86,272.0,572.82,89.0,2.69,72.2
+2020-04-26 17:00:00,13.48,107.0,336.13,53.0,2.14,74.85
+2020-04-26 18:00:00,12.1,0.0,0.0,0.0,2.07,83.15
+2020-04-26 19:00:00,11.01,0.0,-0.0,0.0,1.72,86.1
+2020-04-26 20:00:00,10.03,0.0,-0.0,0.0,1.72,92.5
+2020-04-26 21:00:00,9.38,0.0,-0.0,0.0,2.0,92.45
+2020-04-26 22:00:00,8.91,0.0,-0.0,0.0,2.07,95.85
+2020-04-26 23:00:00,8.61,0.0,-0.0,0.0,1.86,95.85
+2020-04-27 00:00:00,8.12,0.0,-0.0,0.0,1.72,95.8
+2020-04-27 01:00:00,7.29,0.0,-0.0,0.0,1.79,99.4
+2020-04-27 02:00:00,6.87,0.0,-0.0,0.0,1.66,95.8
+2020-04-27 03:00:00,6.35,0.0,-0.0,0.0,1.66,95.8
+2020-04-27 04:00:00,6.02,2.0,0.0,2.0,1.59,95.8
+2020-04-27 05:00:00,7.04,86.0,43.32,77.0,1.31,99.4
+2020-04-27 06:00:00,9.32,177.0,60.29,155.0,1.1,95.85
+2020-04-27 07:00:00,11.74,177.0,5.88,174.0,1.45,89.3
+2020-04-27 08:00:00,13.2,160.0,0.0,160.0,1.86,80.35
+2020-04-27 09:00:00,14.33,287.0,9.65,280.0,2.0,72.3
+2020-04-27 10:00:00,15.06,261.0,1.28,260.0,1.86,67.45
+2020-04-27 11:00:00,16.09,585.0,249.97,386.0,1.93,65.25
+2020-04-27 12:00:00,16.7,558.0,240.35,373.0,2.14,65.35
+2020-04-27 13:00:00,17.4,480.0,193.31,344.0,2.28,65.35
+2020-04-27 14:00:00,17.35,305.0,53.15,273.0,2.55,65.35
+2020-04-27 15:00:00,16.98,193.0,19.05,184.0,2.34,65.35
+2020-04-27 16:00:00,15.55,106.0,6.19,104.0,1.59,77.85
+2020-04-27 17:00:00,14.63,40.0,0.0,40.0,1.31,80.55
+2020-04-27 18:00:00,13.73,0.0,0.0,0.0,1.72,83.35
+2020-04-27 19:00:00,11.64,0.0,-0.0,0.0,1.03,92.55
+2020-04-27 20:00:00,10.83,0.0,-0.0,0.0,1.1,99.4
+2020-04-27 21:00:00,10.18,0.0,-0.0,0.0,0.9,95.9
+2020-04-27 22:00:00,9.19,0.0,-0.0,0.0,1.31,99.4
+2020-04-27 23:00:00,8.7,0.0,-0.0,0.0,1.31,95.85
+2020-04-28 00:00:00,9.75,0.0,-0.0,0.0,0.97,92.45
+2020-04-28 01:00:00,10.72,0.0,-0.0,0.0,0.69,89.25
+2020-04-28 02:00:00,10.68,0.0,-0.0,0.0,0.69,89.25
+2020-04-28 03:00:00,10.43,0.0,-0.0,0.0,0.69,89.25
+2020-04-28 04:00:00,10.23,12.0,18.54,11.0,0.83,92.5
+2020-04-28 05:00:00,10.24,52.0,0.0,52.0,0.9,92.5
+2020-04-28 06:00:00,11.6,79.0,0.0,79.0,0.55,92.55
+2020-04-28 07:00:00,14.59,186.0,7.78,182.0,1.24,77.75
+2020-04-28 08:00:00,15.68,577.0,590.64,201.0,1.31,75.15
+2020-04-28 09:00:00,16.62,617.0,444.55,293.0,1.52,72.7
+2020-04-28 10:00:00,17.49,719.0,577.54,266.0,1.86,70.3
+2020-04-28 11:00:00,18.45,688.0,459.09,321.0,2.14,63.4
+2020-04-28 12:00:00,19.38,678.0,495.51,295.0,2.55,57.1
+2020-04-28 13:00:00,19.94,437.0,128.75,346.0,2.9,53.35
+2020-04-28 14:00:00,20.25,285.0,36.34,263.0,3.38,53.35
+2020-04-28 15:00:00,19.92,285.0,134.53,221.0,3.59,55.2
+2020-04-28 16:00:00,17.62,231.0,306.16,131.0,2.07,70.3
+2020-04-28 17:00:00,17.58,87.0,130.78,65.0,1.93,67.85
+2020-04-28 18:00:00,16.38,0.0,0.0,0.0,1.93,70.1
+2020-04-28 19:00:00,14.74,0.0,-0.0,0.0,2.07,75.0
+2020-04-28 20:00:00,12.98,0.0,-0.0,0.0,2.0,83.25
+2020-04-28 21:00:00,11.48,0.0,-0.0,0.0,2.07,86.15
+2020-04-28 22:00:00,10.29,0.0,-0.0,0.0,2.07,89.2
+2020-04-28 23:00:00,9.43,0.0,-0.0,0.0,2.21,85.95
+2020-04-29 00:00:00,8.95,0.0,-0.0,0.0,2.34,82.85
+2020-04-29 01:00:00,8.47,0.0,-0.0,0.0,2.41,82.75
+2020-04-29 02:00:00,8.04,0.0,-0.0,0.0,2.34,82.7
+2020-04-29 03:00:00,7.56,0.0,-0.0,0.0,2.34,82.65
+2020-04-29 04:00:00,7.23,12.0,0.0,12.0,2.34,82.6
+2020-04-29 05:00:00,8.16,144.0,281.35,83.0,2.14,82.7
+2020-04-29 06:00:00,12.12,287.0,382.89,144.0,2.0,71.95
+2020-04-29 07:00:00,14.8,416.0,401.59,208.0,2.55,69.85
+2020-04-29 08:00:00,16.84,589.0,610.6,198.0,3.31,63.05
+2020-04-29 09:00:00,18.58,721.0,745.52,175.0,4.14,56.95
+2020-04-29 10:00:00,19.9,782.0,750.25,191.0,4.76,51.4
+2020-04-29 11:00:00,20.69,628.0,315.2,375.0,5.38,43.1
+2020-04-29 12:00:00,20.67,183.0,0.0,183.0,5.31,41.55
+2020-04-29 13:00:00,20.61,116.0,0.0,116.0,4.97,41.55
+2020-04-29 14:00:00,20.32,224.0,6.57,220.0,5.1,44.6
+2020-04-29 15:00:00,19.72,303.0,166.98,223.0,4.69,46.1
+2020-04-29 16:00:00,18.65,25.0,0.0,25.0,3.24,51.15
+2020-04-29 17:00:00,18.03,89.0,127.94,67.0,3.17,51.0
+2020-04-29 18:00:00,16.73,0.0,0.0,0.0,2.83,52.65
+2020-04-29 19:00:00,15.23,0.0,-0.0,0.0,2.9,50.35
+2020-04-29 20:00:00,14.33,0.0,-0.0,0.0,3.1,53.95
+2020-04-29 21:00:00,13.6,0.0,-0.0,0.0,2.76,55.9
+2020-04-29 22:00:00,12.61,0.0,-0.0,0.0,2.62,59.95
+2020-04-29 23:00:00,11.66,0.0,-0.0,0.0,2.55,64.35
+2020-04-30 00:00:00,10.86,0.0,-0.0,0.0,2.62,66.65
+2020-04-30 01:00:00,10.27,0.0,-0.0,0.0,2.62,71.6
+2020-04-30 02:00:00,9.74,0.0,-0.0,0.0,2.69,77.0
+2020-04-30 03:00:00,9.26,0.0,-0.0,0.0,2.76,79.85
+2020-04-30 04:00:00,8.76,9.0,0.0,9.0,2.69,82.75
+2020-04-30 05:00:00,9.18,150.0,302.88,83.0,2.62,82.85
+2020-04-30 06:00:00,10.61,301.0,431.63,138.0,2.97,77.15
+2020-04-30 07:00:00,12.1,439.0,471.39,193.0,3.38,77.35
+2020-04-30 08:00:00,13.44,625.0,726.67,157.0,3.45,72.2
+2020-04-30 09:00:00,14.86,631.0,452.54,298.0,3.72,67.35
+2020-04-30 10:00:00,16.17,615.0,305.93,373.0,4.07,60.75
+2020-04-30 11:00:00,17.19,796.0,729.67,208.0,4.28,58.7
+2020-04-30 12:00:00,18.08,809.0,858.52,140.0,4.34,52.9
+2020-04-30 13:00:00,18.37,732.0,842.83,131.0,4.34,51.0
+2020-04-30 14:00:00,18.42,603.0,773.09,130.0,5.1,45.85
+2020-04-30 15:00:00,18.06,436.0,619.8,137.0,4.76,47.4
+2020-04-30 16:00:00,14.48,280.0,539.5,100.0,3.6,46.83
+2020-04-30 17:00:00,14.35,105.0,216.33,67.0,3.44,50.03
+2020-04-30 18:00:00,14.22,0.0,0.0,0.0,3.28,53.23
+2020-04-30 19:00:00,14.09,0.0,-0.0,0.0,3.11,56.43
+2020-04-30 20:00:00,13.95,0.0,-0.0,0.0,2.95,59.62
+2020-04-30 21:00:00,13.82,0.0,-0.0,0.0,2.79,62.82
+2020-04-30 22:00:00,13.69,0.0,-0.0,0.0,2.63,66.02
+2020-04-30 23:00:00,13.56,0.0,-0.0,0.0,2.47,69.22
+2020-05-01 00:00:00,13.43,0.0,-0.0,0.0,2.31,72.42
+2020-05-01 01:00:00,13.3,0.0,-0.0,0.0,2.15,75.62
+2020-05-01 02:00:00,13.17,0.0,-0.0,0.0,1.99,78.81
+2020-05-01 03:00:00,13.03,0.0,-0.0,0.0,1.83,82.01
+2020-05-01 04:00:00,12.9,22.0,27.7,20.0,1.67,85.21
+2020-05-01 05:00:00,12.77,152.0,278.57,88.0,1.51,88.41
+2020-05-01 06:00:00,12.64,318.0,497.8,126.0,1.35,91.61
+2020-05-01 07:00:00,12.51,484.0,644.08,143.0,1.19,94.81
+2020-05-01 08:00:00,20.64,624.0,715.65,158.0,1.93,61.6
+2020-05-01 09:00:00,22.35,741.0,794.55,151.0,2.07,55.8
+2020-05-01 10:00:00,23.76,802.0,802.58,162.0,2.0,50.55
+2020-05-01 11:00:00,24.82,828.0,832.5,152.0,1.93,47.4
+2020-05-01 12:00:00,25.43,770.0,738.55,190.0,1.72,42.75
+2020-05-01 13:00:00,25.53,661.0,604.86,226.0,1.38,41.25
+2020-05-01 14:00:00,25.69,598.0,749.09,135.0,1.31,39.95
+2020-05-01 15:00:00,25.53,448.0,668.81,121.0,1.17,42.75
+2020-05-01 16:00:00,25.23,285.0,549.16,98.0,0.55,50.95
+2020-05-01 17:00:00,24.46,125.0,344.33,62.0,1.24,54.35
+2020-05-01 18:00:00,22.2,0.0,0.0,0.0,1.38,66.35
+2020-05-01 19:00:00,19.13,0.0,-0.0,0.0,1.93,70.55
+2020-05-01 20:00:00,17.48,0.0,-0.0,0.0,2.0,78.1
+2020-05-01 21:00:00,16.12,0.0,-0.0,0.0,2.14,83.6
+2020-05-01 22:00:00,15.16,0.0,-0.0,0.0,1.86,89.55
+2020-05-01 23:00:00,14.51,0.0,-0.0,0.0,1.79,89.5
+2020-05-02 00:00:00,13.81,0.0,-0.0,0.0,1.59,95.95
+2020-05-02 01:00:00,13.44,0.0,-0.0,0.0,1.45,92.65
+2020-05-02 02:00:00,13.3,0.0,-0.0,0.0,1.38,95.95
+2020-05-02 03:00:00,13.47,0.0,-0.0,0.0,1.31,92.65
+2020-05-02 04:00:00,12.85,25.0,39.19,22.0,1.52,92.6
+2020-05-02 05:00:00,13.39,151.0,256.54,91.0,1.31,95.95
+2020-05-02 06:00:00,17.24,317.0,479.98,130.0,1.03,80.85
+2020-05-02 07:00:00,19.75,486.0,643.41,143.0,1.1,73.15
+2020-05-02 08:00:00,21.6,633.0,742.45,147.0,1.45,61.85
+2020-05-02 09:00:00,23.22,743.0,793.78,151.0,1.79,58.0
+2020-05-02 10:00:00,24.69,804.0,800.73,163.0,2.14,52.6
+2020-05-02 11:00:00,25.88,825.0,819.63,157.0,2.41,49.3
+2020-05-02 12:00:00,26.67,776.0,752.28,183.0,2.69,43.15
+2020-05-02 13:00:00,25.97,695.0,713.15,180.0,3.31,46.0
+2020-05-02 14:00:00,25.05,581.0,671.35,164.0,3.1,52.75
+2020-05-02 15:00:00,25.1,232.0,42.67,211.0,3.52,54.55
+2020-05-02 16:00:00,24.24,161.0,55.25,142.0,3.31,60.25
+2020-05-02 17:00:00,22.92,58.0,10.72,56.0,2.83,66.45
+2020-05-02 18:00:00,21.56,5.0,0.0,5.0,2.48,71.0
+2020-05-02 19:00:00,20.07,0.0,-0.0,0.0,2.41,68.3
+2020-05-02 20:00:00,18.77,0.0,-0.0,0.0,2.21,75.55
+2020-05-02 21:00:00,17.6,0.0,-0.0,0.0,2.21,80.85
+2020-05-02 22:00:00,16.56,0.0,-0.0,0.0,1.72,80.8
+2020-05-02 23:00:00,14.99,0.0,-0.0,0.0,1.79,86.5
+2020-05-03 00:00:00,14.56,0.0,-0.0,0.0,2.41,89.5
+2020-05-03 01:00:00,14.24,0.0,-0.0,0.0,2.41,92.7
+2020-05-03 02:00:00,13.85,0.0,-0.0,0.0,2.34,95.95
+2020-05-03 03:00:00,13.61,0.0,-0.0,0.0,2.48,95.95
+2020-05-03 04:00:00,13.42,5.0,0.0,5.0,2.48,92.65
+2020-05-03 05:00:00,14.0,40.0,0.0,40.0,2.97,92.7
+2020-05-03 06:00:00,14.94,128.0,5.08,126.0,3.45,89.55
+2020-05-03 07:00:00,15.77,137.0,0.0,137.0,3.24,89.6
+2020-05-03 08:00:00,16.7,291.0,24.32,275.0,2.83,89.65
+2020-05-03 09:00:00,16.67,477.0,148.2,366.0,3.52,89.65
+2020-05-03 10:00:00,17.14,226.0,0.0,226.0,3.86,86.65
+2020-05-03 11:00:00,17.27,427.0,55.02,382.0,3.72,86.65
+2020-05-03 12:00:00,17.01,126.0,0.0,126.0,3.86,83.7
+2020-05-03 13:00:00,17.2,319.0,22.07,303.0,3.93,80.85
+2020-05-03 14:00:00,17.03,288.0,33.65,267.0,3.59,78.1
+2020-05-03 15:00:00,17.28,315.0,177.68,227.0,3.17,78.1
+2020-05-03 16:00:00,17.44,53.0,0.0,53.0,3.17,75.4
+2020-05-03 17:00:00,17.31,12.0,0.0,12.0,2.41,75.4
+2020-05-03 18:00:00,16.68,1.0,0.0,1.0,2.07,75.3
+2020-05-03 19:00:00,15.29,0.0,-0.0,0.0,1.72,86.5
+2020-05-03 20:00:00,14.58,0.0,-0.0,0.0,1.72,86.45
+2020-05-03 21:00:00,14.0,0.0,-0.0,0.0,1.86,89.5
+2020-05-03 22:00:00,13.48,0.0,-0.0,0.0,2.28,89.45
+2020-05-03 23:00:00,13.32,0.0,-0.0,0.0,2.48,86.3
+2020-05-04 00:00:00,12.97,0.0,-0.0,0.0,2.55,83.25
+2020-05-04 01:00:00,12.66,0.0,-0.0,0.0,2.62,83.25
+2020-05-04 02:00:00,12.16,0.0,-0.0,0.0,2.62,83.15
+2020-05-04 03:00:00,11.59,0.0,-0.0,0.0,2.41,83.1
+2020-05-04 04:00:00,11.05,45.0,200.01,28.0,2.21,83.05
+2020-05-04 05:00:00,11.35,115.0,70.28,98.0,1.93,86.1
+2020-05-04 06:00:00,13.31,349.0,599.29,111.0,2.14,77.5
+2020-05-04 07:00:00,14.95,510.0,701.64,131.0,2.07,72.45
+2020-05-04 08:00:00,16.38,650.0,760.72,147.0,2.28,60.75
+2020-05-04 09:00:00,17.36,593.0,332.42,343.0,2.69,50.85
+2020-05-04 10:00:00,18.07,752.0,602.62,266.0,2.9,47.4
+2020-05-04 11:00:00,18.68,781.0,644.51,252.0,3.66,44.2
+2020-05-04 12:00:00,19.12,658.0,394.21,345.0,3.59,41.15
+2020-05-04 13:00:00,19.35,567.0,320.08,334.0,3.38,41.15
+2020-05-04 14:00:00,19.35,513.0,405.03,259.0,2.97,41.15
+2020-05-04 15:00:00,19.37,452.0,626.01,140.0,2.55,42.7
+2020-05-04 16:00:00,19.19,293.0,530.59,107.0,1.93,44.3
+2020-05-04 17:00:00,18.37,140.0,407.93,61.0,0.83,63.3
+2020-05-04 18:00:00,18.32,9.0,0.0,9.0,0.28,49.15
+2020-05-04 19:00:00,14.22,0.0,-0.0,0.0,1.86,72.3
+2020-05-04 20:00:00,12.34,0.0,-0.0,0.0,2.21,74.6
+2020-05-04 21:00:00,11.26,0.0,-0.0,0.0,2.28,77.2
+2020-05-04 22:00:00,10.4,0.0,-0.0,0.0,2.21,77.15
+2020-05-04 23:00:00,9.67,0.0,-0.0,0.0,2.14,82.9
+2020-05-05 00:00:00,9.12,0.0,-0.0,0.0,2.21,82.85
+2020-05-05 01:00:00,8.65,0.0,-0.0,0.0,2.28,82.75
+2020-05-05 02:00:00,8.37,0.0,-0.0,0.0,2.28,82.75
+2020-05-05 03:00:00,8.08,0.0,-0.0,0.0,2.21,82.7
+2020-05-05 04:00:00,7.68,38.0,89.8,30.0,2.07,85.8
+2020-05-05 05:00:00,9.05,178.0,374.36,86.0,1.59,85.95
+2020-05-05 06:00:00,13.38,335.0,516.51,128.0,0.97,74.75
+2020-05-05 07:00:00,16.09,499.0,651.26,145.0,0.76,65.25
+2020-05-05 08:00:00,17.99,628.0,680.31,176.0,0.55,58.9
+2020-05-05 09:00:00,19.64,760.0,810.53,148.0,0.83,53.25
+2020-05-05 10:00:00,20.64,422.0,53.13,379.0,0.83,48.05
+2020-05-05 11:00:00,20.69,276.0,1.21,275.0,0.97,49.8
+2020-05-05 12:00:00,18.63,390.0,37.65,360.0,2.9,65.65
+2020-05-05 13:00:00,16.7,65.0,0.0,65.0,2.34,78.0
+2020-05-05 14:00:00,16.68,59.0,0.0,59.0,1.31,75.3
+2020-05-05 15:00:00,16.13,76.0,0.0,76.0,1.52,77.95
+2020-05-05 16:00:00,15.29,34.0,0.0,34.0,0.9,83.5
+2020-05-05 17:00:00,14.71,26.0,0.0,26.0,0.34,86.45
+2020-05-05 18:00:00,13.95,10.0,23.73,9.0,0.34,89.5
+2020-05-05 19:00:00,12.78,0.0,-0.0,0.0,1.24,95.95
+2020-05-05 20:00:00,12.24,0.0,-0.0,0.0,1.31,99.4
+2020-05-05 21:00:00,11.65,0.0,-0.0,0.0,1.1,99.4
+2020-05-05 22:00:00,11.27,0.0,-0.0,0.0,1.24,100.0
+2020-05-05 23:00:00,10.91,0.0,-0.0,0.0,1.79,99.35
+2020-05-06 00:00:00,10.05,0.0,-0.0,0.0,2.07,99.4
+2020-05-06 01:00:00,8.23,0.0,-0.0,0.0,2.14,99.4
+2020-05-06 02:00:00,6.8,0.0,-0.0,0.0,2.34,95.8
+2020-05-06 03:00:00,6.15,0.0,-0.0,0.0,2.0,92.3
+2020-05-06 04:00:00,5.75,18.0,0.0,18.0,1.86,95.75
+2020-05-06 05:00:00,5.61,30.0,0.0,30.0,1.59,92.3
+2020-05-06 06:00:00,5.7,59.0,0.0,59.0,1.31,92.3
+2020-05-06 07:00:00,5.89,125.0,0.0,125.0,1.66,88.95
+2020-05-06 08:00:00,6.38,223.0,1.5,222.0,1.38,85.75
+2020-05-06 09:00:00,6.98,251.0,1.32,250.0,1.45,89.0
+2020-05-06 10:00:00,7.85,209.0,0.0,209.0,1.38,85.8
+2020-05-06 11:00:00,8.52,324.0,7.26,318.0,1.24,79.75
+2020-05-06 12:00:00,8.86,293.0,5.0,289.0,0.83,82.75
+2020-05-06 13:00:00,9.36,129.0,0.0,129.0,1.17,85.95
+2020-05-06 14:00:00,9.46,55.0,0.0,55.0,1.52,82.9
+2020-05-06 15:00:00,9.7,78.0,0.0,78.0,1.93,82.9
+2020-05-06 16:00:00,9.55,60.0,0.0,60.0,2.34,82.9
+2020-05-06 17:00:00,9.37,53.0,0.0,53.0,2.28,85.95
+2020-05-06 18:00:00,9.06,5.0,0.0,5.0,1.86,85.95
+2020-05-06 19:00:00,7.3,0.0,-0.0,0.0,1.66,95.8
+2020-05-06 20:00:00,7.17,0.0,-0.0,0.0,1.59,95.8
+2020-05-06 21:00:00,7.05,0.0,-0.0,0.0,1.59,95.8
+2020-05-06 22:00:00,6.87,0.0,-0.0,0.0,1.59,92.35
+2020-05-06 23:00:00,6.73,0.0,-0.0,0.0,1.31,92.35
+2020-05-07 00:00:00,6.58,0.0,-0.0,0.0,1.1,92.35
+2020-05-07 01:00:00,6.65,0.0,-0.0,0.0,0.97,92.35
+2020-05-07 02:00:00,6.63,0.0,-0.0,0.0,0.9,92.35
+2020-05-07 03:00:00,6.15,0.0,-0.0,0.0,1.03,95.8
+2020-05-07 04:00:00,6.12,10.0,0.0,10.0,0.97,95.8
+2020-05-07 05:00:00,6.92,128.0,90.83,105.0,1.79,92.35
+2020-05-07 06:00:00,8.05,114.0,0.0,114.0,1.66,89.05
+2020-05-07 07:00:00,8.71,107.0,0.0,107.0,0.9,89.1
+2020-05-07 08:00:00,9.56,226.0,1.49,225.0,0.9,82.9
+2020-05-07 09:00:00,10.83,376.0,39.43,346.0,0.9,80.05
+2020-05-07 10:00:00,11.98,275.0,1.23,274.0,1.1,71.95
+2020-05-07 11:00:00,12.9,434.0,51.87,391.0,1.52,66.95
+2020-05-07 12:00:00,13.55,438.0,66.07,385.0,1.72,64.75
+2020-05-07 13:00:00,14.2,574.0,321.9,337.0,1.72,60.3
+2020-05-07 14:00:00,14.29,423.0,182.46,307.0,1.86,60.3
+2020-05-07 15:00:00,14.21,323.0,165.52,239.0,1.79,60.3
+2020-05-07 16:00:00,13.94,285.0,435.82,128.0,1.93,60.3
+2020-05-07 17:00:00,13.33,106.0,117.64,82.0,2.14,64.65
+2020-05-07 18:00:00,12.57,18.0,101.07,13.0,2.14,66.95
+2020-05-07 19:00:00,11.41,0.0,-0.0,0.0,2.0,71.85
+2020-05-07 20:00:00,10.57,0.0,-0.0,0.0,1.86,77.15
+2020-05-07 21:00:00,9.63,0.0,-0.0,0.0,1.86,82.9
+2020-05-07 22:00:00,9.04,0.0,-0.0,0.0,1.93,85.95
+2020-05-07 23:00:00,8.97,0.0,-0.0,0.0,2.0,82.85
+2020-05-08 00:00:00,8.96,0.0,-0.0,0.0,2.0,82.85
+2020-05-08 01:00:00,8.83,0.0,-0.0,0.0,2.07,89.1
+2020-05-08 02:00:00,8.71,0.0,-0.0,0.0,2.07,89.1
+2020-05-08 03:00:00,8.44,0.0,-0.0,0.0,2.14,89.1
+2020-05-08 04:00:00,8.08,8.0,0.0,8.0,2.21,89.05
+2020-05-08 05:00:00,8.81,52.0,0.0,52.0,2.28,89.1
+2020-05-08 06:00:00,10.43,255.0,165.4,187.0,2.55,80.05
+2020-05-08 07:00:00,12.8,465.0,468.15,206.0,2.48,83.25
+2020-05-08 08:00:00,14.58,408.0,118.79,328.0,2.76,69.85
+2020-05-08 09:00:00,15.76,533.0,206.91,375.0,2.62,70.0
+2020-05-08 10:00:00,16.52,370.0,22.02,352.0,2.55,60.85
+2020-05-08 11:00:00,17.18,554.0,163.54,418.0,2.34,54.7
+2020-05-08 12:00:00,18.13,270.0,1.24,269.0,2.48,51.0
+2020-05-08 13:00:00,18.93,232.0,0.0,232.0,2.34,47.55
+2020-05-08 14:00:00,19.47,314.0,43.85,286.0,2.07,44.3
+2020-05-08 15:00:00,19.24,426.0,470.18,186.0,1.72,45.95
+2020-05-08 16:00:00,19.0,309.0,558.63,106.0,1.79,49.45
+2020-05-08 17:00:00,18.29,159.0,467.72,62.0,1.66,58.9
+2020-05-08 18:00:00,16.88,19.0,75.37,15.0,2.0,60.85
+2020-05-08 19:00:00,15.31,0.0,-0.0,0.0,2.76,60.5
+2020-05-08 20:00:00,14.52,0.0,-0.0,0.0,2.9,58.25
+2020-05-08 21:00:00,13.93,0.0,-0.0,0.0,3.1,60.3
+2020-05-08 22:00:00,13.47,0.0,-0.0,0.0,3.17,62.45
+2020-05-08 23:00:00,13.02,0.0,-0.0,0.0,3.24,64.65
+2020-05-09 00:00:00,12.67,0.0,-0.0,0.0,3.38,66.95
+2020-05-09 01:00:00,12.44,0.0,-0.0,0.0,3.52,69.45
+2020-05-09 02:00:00,12.16,0.0,-0.0,0.0,3.59,69.35
+2020-05-09 03:00:00,11.88,0.0,-0.0,0.0,3.59,71.85
+2020-05-09 04:00:00,11.64,9.0,0.0,9.0,3.45,71.85
+2020-05-09 05:00:00,12.29,79.0,3.84,78.0,3.17,71.95
+2020-05-09 06:00:00,13.91,250.0,152.03,187.0,2.83,69.65
+2020-05-09 07:00:00,15.79,363.0,183.36,261.0,2.83,70.0
+2020-05-09 08:00:00,17.19,217.0,1.48,216.0,2.62,65.45
+2020-05-09 09:00:00,18.61,244.0,1.3,243.0,2.28,63.4
+2020-05-09 10:00:00,20.14,384.0,29.26,360.0,2.48,59.35
+2020-05-09 11:00:00,21.14,396.0,31.17,370.0,3.24,55.55
+2020-05-09 12:00:00,21.53,562.0,206.86,395.0,3.59,53.75
+2020-05-09 13:00:00,21.76,462.0,133.51,363.0,3.52,53.75
+2020-05-09 14:00:00,21.6,277.0,21.83,263.0,3.03,51.9
+2020-05-09 15:00:00,21.72,42.0,0.0,42.0,3.17,51.9
+2020-05-09 16:00:00,21.3,222.0,163.71,162.0,2.21,57.55
+2020-05-09 17:00:00,20.51,111.0,128.13,84.0,1.45,63.8
+2020-05-09 18:00:00,19.22,18.0,52.97,15.0,1.66,70.55
+2020-05-09 19:00:00,16.82,0.0,-0.0,0.0,2.0,83.65
+2020-05-09 20:00:00,15.53,0.0,-0.0,0.0,2.07,86.5
+2020-05-09 21:00:00,14.81,0.0,-0.0,0.0,2.07,89.5
+2020-05-09 22:00:00,14.12,0.0,-0.0,0.0,2.07,89.5
+2020-05-09 23:00:00,13.5,0.0,-0.0,0.0,2.07,89.45
+2020-05-10 00:00:00,13.51,0.0,-0.0,0.0,2.14,89.45
+2020-05-10 01:00:00,13.27,0.0,-0.0,0.0,2.21,92.65
+2020-05-10 02:00:00,12.52,0.0,-0.0,0.0,2.07,92.6
+2020-05-10 03:00:00,11.79,0.0,-0.0,0.0,2.07,95.9
+2020-05-10 04:00:00,11.41,63.0,249.64,36.0,2.0,95.9
+2020-05-10 05:00:00,12.85,204.0,466.42,81.0,1.66,95.95
+2020-05-10 06:00:00,16.55,295.0,287.38,175.0,1.52,83.65
+2020-05-10 07:00:00,19.12,514.0,668.75,140.0,1.86,78.3
+2020-05-10 08:00:00,20.77,652.0,739.22,150.0,2.21,68.4
+2020-05-10 09:00:00,22.14,752.0,760.78,167.0,2.55,57.75
+2020-05-10 10:00:00,22.86,759.0,610.21,257.0,2.55,55.9
+2020-05-10 11:00:00,23.88,726.0,487.69,318.0,2.97,50.55
+2020-05-10 12:00:00,24.8,564.0,211.16,393.0,3.79,44.15
+2020-05-10 13:00:00,24.96,449.0,118.27,361.0,3.72,44.15
+2020-05-10 14:00:00,24.71,477.0,293.5,288.0,3.1,45.75
+2020-05-10 15:00:00,24.59,304.0,125.92,239.0,2.48,49.05
+2020-05-10 16:00:00,24.21,108.0,2.71,107.0,2.0,54.35
+2020-05-10 17:00:00,23.26,107.0,102.8,85.0,1.72,62.15
+2020-05-10 18:00:00,21.92,21.0,66.5,17.0,2.14,64.0
+2020-05-10 19:00:00,20.12,0.0,-0.0,0.0,2.34,68.3
+2020-05-10 20:00:00,18.97,0.0,-0.0,0.0,2.48,72.95
+2020-05-10 21:00:00,18.2,0.0,-0.0,0.0,2.62,75.45
+2020-05-10 22:00:00,17.75,0.0,-0.0,0.0,2.76,78.1
+2020-05-10 23:00:00,17.62,0.0,-0.0,0.0,2.9,78.1
+2020-05-11 00:00:00,17.77,0.0,-0.0,0.0,3.03,78.1
+2020-05-11 01:00:00,17.89,0.0,-0.0,0.0,3.17,75.4
+2020-05-11 02:00:00,18.0,0.0,-0.0,0.0,3.1,72.9
+2020-05-11 03:00:00,17.84,0.0,-0.0,0.0,3.1,75.4
+2020-05-11 04:00:00,17.77,9.0,0.0,9.0,3.03,75.4
+2020-05-11 05:00:00,18.39,145.0,127.33,111.0,2.9,75.45
+2020-05-11 06:00:00,20.21,128.0,2.38,127.0,2.48,68.3
+2020-05-11 07:00:00,22.18,197.0,5.34,194.0,2.76,66.35
+2020-05-11 08:00:00,24.05,439.0,167.21,325.0,3.1,60.25
+2020-05-11 09:00:00,25.6,544.0,230.72,366.0,3.1,54.7
+2020-05-11 10:00:00,26.8,648.0,345.41,363.0,3.17,53.1
+2020-05-11 11:00:00,27.54,821.0,761.61,182.0,3.17,48.0
+2020-05-11 12:00:00,28.08,803.0,794.11,158.0,3.1,43.4
+2020-05-11 13:00:00,28.29,738.0,800.96,140.0,2.97,43.4
+2020-05-11 14:00:00,28.55,313.0,44.85,284.0,3.17,41.95
+2020-05-11 15:00:00,28.46,178.0,5.78,175.0,3.38,43.4
+2020-05-11 16:00:00,26.7,28.0,0.0,28.0,2.28,53.1
+2020-05-11 17:00:00,25.8,14.0,0.0,14.0,2.55,56.6
+2020-05-11 18:00:00,24.36,2.0,0.0,2.0,2.48,60.25
+2020-05-11 19:00:00,21.48,0.0,-0.0,0.0,2.21,78.55
+2020-05-11 20:00:00,19.82,0.0,-0.0,0.0,0.76,89.85
+2020-05-11 21:00:00,19.06,0.0,-0.0,0.0,2.34,86.8
+2020-05-11 22:00:00,18.11,0.0,-0.0,0.0,4.0,96.05
+2020-05-11 23:00:00,16.43,0.0,-0.0,0.0,4.14,96.05
+2020-05-12 00:00:00,15.19,0.0,-0.0,0.0,3.66,92.75
+2020-05-12 01:00:00,14.13,0.0,-0.0,0.0,3.38,96.0
+2020-05-12 02:00:00,13.28,0.0,-0.0,0.0,3.79,92.65
+2020-05-12 03:00:00,12.51,0.0,-0.0,0.0,3.59,92.6
+2020-05-12 04:00:00,11.8,6.0,0.0,6.0,3.72,92.55
+2020-05-12 05:00:00,11.36,29.0,0.0,29.0,3.59,89.3
+2020-05-12 06:00:00,10.94,63.0,0.0,63.0,4.14,80.1
+2020-05-12 07:00:00,10.79,100.0,0.0,100.0,3.79,86.05
+2020-05-12 08:00:00,10.42,156.0,0.0,156.0,4.21,77.15
+2020-05-12 09:00:00,10.21,360.0,28.43,338.0,4.41,71.6
+2020-05-12 10:00:00,10.72,167.0,0.0,167.0,4.48,66.55
+2020-05-12 11:00:00,11.72,673.0,349.43,379.0,4.97,57.55
+2020-05-12 12:00:00,12.65,506.0,125.21,404.0,5.24,51.65
+2020-05-12 13:00:00,13.26,512.0,196.24,365.0,5.31,48.0
+2020-05-12 14:00:00,13.58,465.0,249.54,303.0,5.31,42.95
+2020-05-12 15:00:00,13.33,418.0,412.04,203.0,5.24,41.2
+2020-05-12 16:00:00,12.73,213.0,122.48,167.0,5.17,42.7
+2020-05-12 17:00:00,11.88,105.0,77.12,88.0,4.41,47.6
+2020-05-12 18:00:00,11.12,26.0,89.5,20.0,3.72,49.3
+2020-05-12 19:00:00,10.02,0.0,-0.0,0.0,3.72,55.05
+2020-05-12 20:00:00,9.52,0.0,-0.0,0.0,3.59,57.05
+2020-05-12 21:00:00,8.69,0.0,-0.0,0.0,3.38,61.3
+2020-05-12 22:00:00,8.15,0.0,-0.0,0.0,3.24,66.05
+2020-05-12 23:00:00,7.52,0.0,-0.0,0.0,3.24,68.5
+2020-05-13 00:00:00,6.91,0.0,-0.0,0.0,3.24,68.4
+2020-05-13 01:00:00,6.51,0.0,-0.0,0.0,3.17,68.4
+2020-05-13 02:00:00,5.99,0.0,-0.0,0.0,3.1,70.95
+2020-05-13 03:00:00,5.56,0.0,-0.0,0.0,3.03,73.65
+2020-05-13 04:00:00,5.27,64.0,168.83,44.0,2.97,76.4
+2020-05-13 05:00:00,5.39,110.0,25.61,103.0,3.45,73.65
+2020-05-13 06:00:00,6.04,140.0,2.34,139.0,4.28,68.3
+2020-05-13 07:00:00,6.64,170.0,0.0,170.0,3.93,71.05
+2020-05-13 08:00:00,7.36,300.0,18.93,287.0,3.72,68.5
+2020-05-13 09:00:00,7.88,264.0,1.29,263.0,3.72,66.05
+2020-05-13 10:00:00,8.99,224.0,0.0,224.0,3.86,61.45
+2020-05-13 11:00:00,9.66,224.0,0.0,224.0,3.86,59.25
+2020-05-13 12:00:00,10.12,211.0,0.0,211.0,3.79,55.05
+2020-05-13 13:00:00,10.53,229.0,0.0,229.0,3.66,55.15
+2020-05-13 14:00:00,10.88,305.0,30.69,285.0,3.38,53.1
+2020-05-13 15:00:00,11.03,256.0,45.76,232.0,3.03,51.25
+2020-05-13 16:00:00,10.69,151.0,18.49,144.0,2.62,53.1
+2020-05-13 17:00:00,10.52,79.0,13.42,76.0,2.41,53.1
+2020-05-13 18:00:00,10.04,18.0,14.2,17.0,1.86,55.05
+2020-05-13 19:00:00,8.65,0.0,-0.0,0.0,1.31,66.15
+2020-05-13 20:00:00,7.49,0.0,-0.0,0.0,0.97,76.7
+2020-05-13 21:00:00,7.67,0.0,-0.0,0.0,0.76,68.5
+2020-05-13 22:00:00,7.53,0.0,-0.0,0.0,0.55,68.5
+2020-05-13 23:00:00,7.14,0.0,-0.0,0.0,0.69,71.05
+2020-05-14 00:00:00,6.77,0.0,-0.0,0.0,0.76,71.05
+2020-05-14 01:00:00,6.51,0.0,-0.0,0.0,0.83,71.05
+2020-05-14 02:00:00,6.18,0.0,-0.0,0.0,0.83,73.7
+2020-05-14 03:00:00,5.63,0.0,-0.0,0.0,0.9,76.5
+2020-05-14 04:00:00,4.31,80.0,345.11,38.0,1.17,82.3
+2020-05-14 05:00:00,5.53,239.0,597.02,74.0,0.76,82.5
+2020-05-14 06:00:00,8.38,407.0,715.03,100.0,0.9,71.35
+2020-05-14 07:00:00,9.45,570.0,792.69,118.0,0.83,68.9
+2020-05-14 08:00:00,11.04,710.0,839.92,131.0,1.31,59.6
+2020-05-14 09:00:00,12.11,763.0,699.92,218.0,1.52,55.5
+2020-05-14 10:00:00,12.63,442.0,52.88,398.0,1.52,51.65
+2020-05-14 11:00:00,13.2,617.0,226.98,425.0,1.66,49.85
+2020-05-14 12:00:00,13.29,487.0,93.99,410.0,1.72,49.85
+2020-05-14 13:00:00,13.81,377.0,41.12,346.0,1.52,48.15
+2020-05-14 14:00:00,13.93,289.0,21.4,275.0,1.59,46.5
+2020-05-14 15:00:00,14.47,373.0,240.9,246.0,1.79,44.9
+2020-05-14 16:00:00,14.22,304.0,422.15,143.0,1.72,46.5
+2020-05-14 17:00:00,13.79,120.0,110.27,95.0,1.24,53.85
+2020-05-14 18:00:00,12.88,38.0,217.01,22.0,1.24,62.2
+2020-05-14 19:00:00,10.71,0.0,-0.0,0.0,1.93,66.55
+2020-05-14 20:00:00,8.78,0.0,-0.0,0.0,1.93,76.85
+2020-05-14 21:00:00,7.52,0.0,-0.0,0.0,1.93,79.65
+2020-05-14 22:00:00,6.88,0.0,-0.0,0.0,1.93,79.55
+2020-05-14 23:00:00,6.46,0.0,-0.0,0.0,1.93,79.55
+2020-05-15 00:00:00,5.74,0.0,-0.0,0.0,2.0,82.5
+2020-05-15 01:00:00,5.13,0.0,-0.0,0.0,2.0,85.6
+2020-05-15 02:00:00,5.04,0.0,-0.0,0.0,2.0,85.6
+2020-05-15 03:00:00,4.81,0.0,-0.0,0.0,2.07,88.85
+2020-05-15 04:00:00,4.76,15.0,0.0,15.0,2.0,88.85
+2020-05-15 05:00:00,6.94,38.0,0.0,38.0,1.66,85.75
+2020-05-15 06:00:00,10.78,91.0,0.0,91.0,1.59,71.7
+2020-05-15 07:00:00,12.67,311.0,75.08,268.0,1.86,64.55
+2020-05-15 08:00:00,13.97,240.0,2.89,238.0,2.97,48.25
+2020-05-15 09:00:00,14.71,172.0,0.0,172.0,3.17,44.9
+2020-05-15 10:00:00,15.05,481.0,82.71,412.0,3.03,43.4
+2020-05-15 11:00:00,15.2,449.0,53.06,404.0,3.17,43.4
+2020-05-15 12:00:00,15.24,601.0,236.18,407.0,2.97,45.05
+2020-05-15 13:00:00,15.24,703.0,596.45,252.0,3.1,45.05
+2020-05-15 14:00:00,15.63,632.0,698.96,173.0,3.1,45.15
+2020-05-15 15:00:00,15.89,418.0,368.04,223.0,2.97,43.5
+2020-05-15 16:00:00,16.15,107.0,0.0,107.0,2.9,40.5
+2020-05-15 17:00:00,14.65,80.0,13.06,77.0,2.62,50.25
+2020-05-15 18:00:00,12.92,25.0,38.96,22.0,2.21,62.3
+2020-05-15 19:00:00,10.87,0.0,-0.0,0.0,2.07,80.05
+2020-05-15 20:00:00,10.08,0.0,-0.0,0.0,2.28,79.95
+2020-05-15 21:00:00,9.36,0.0,-0.0,0.0,2.41,85.95
+2020-05-15 22:00:00,9.15,0.0,-0.0,0.0,2.62,85.95
+2020-05-15 23:00:00,8.91,0.0,-0.0,0.0,2.69,82.85
+2020-05-16 00:00:00,8.48,0.0,-0.0,0.0,2.76,85.9
+2020-05-16 01:00:00,7.89,0.0,-0.0,0.0,3.1,85.85
+2020-05-16 02:00:00,7.38,0.0,-0.0,0.0,3.31,85.8
+2020-05-16 03:00:00,6.87,0.0,-0.0,0.0,3.17,85.75
+2020-05-16 04:00:00,6.71,7.0,0.0,7.0,3.24,85.75
+2020-05-16 05:00:00,6.96,80.0,0.0,80.0,3.66,89.0
+2020-05-16 06:00:00,7.36,74.0,0.0,74.0,3.72,89.0
+2020-05-16 07:00:00,7.7,202.0,3.48,200.0,4.48,82.65
+2020-05-16 08:00:00,8.32,191.0,0.0,191.0,4.76,76.8
+2020-05-16 09:00:00,9.08,208.0,0.0,208.0,5.31,66.25
+2020-05-16 10:00:00,9.95,173.0,0.0,173.0,5.45,61.65
+2020-05-16 11:00:00,10.14,229.0,0.0,229.0,5.17,59.35
+2020-05-16 12:00:00,10.91,206.0,0.0,206.0,5.17,55.3
+2020-05-16 13:00:00,11.61,370.0,35.6,343.0,5.45,53.35
+2020-05-16 14:00:00,11.85,480.0,253.38,313.0,5.1,55.4
+2020-05-16 15:00:00,12.06,431.0,403.82,216.0,5.24,51.5
+2020-05-16 16:00:00,11.79,355.0,671.82,95.0,5.31,51.35
+2020-05-16 17:00:00,10.82,155.0,270.65,92.0,4.97,59.5
+2020-05-16 18:00:00,9.97,14.0,0.0,14.0,3.86,61.65
+2020-05-16 19:00:00,8.79,0.0,-0.0,0.0,4.07,63.7
+2020-05-16 20:00:00,8.04,0.0,-0.0,0.0,4.07,68.6
+2020-05-16 21:00:00,7.46,0.0,-0.0,0.0,3.86,71.15
+2020-05-16 22:00:00,7.15,0.0,-0.0,0.0,3.72,76.65
+2020-05-16 23:00:00,6.69,0.0,-0.0,0.0,3.79,76.65
+2020-05-17 00:00:00,6.01,0.0,-0.0,0.0,3.66,76.55
+2020-05-17 01:00:00,5.6,0.0,-0.0,0.0,3.52,79.4
+2020-05-17 02:00:00,5.01,0.0,-0.0,0.0,3.31,79.35
+2020-05-17 03:00:00,4.64,0.0,-0.0,0.0,3.24,82.35
+2020-05-17 04:00:00,4.49,79.0,244.6,47.0,3.31,82.35
+2020-05-17 05:00:00,4.99,236.0,519.57,88.0,3.24,79.35
+2020-05-17 06:00:00,5.66,333.0,331.65,188.0,4.14,73.65
+2020-05-17 07:00:00,6.35,464.0,372.29,249.0,4.69,70.95
+2020-05-17 08:00:00,7.28,572.0,379.21,308.0,4.97,61.0
+2020-05-17 09:00:00,8.35,641.0,357.89,360.0,4.69,54.55
+2020-05-17 10:00:00,8.68,622.0,242.14,419.0,4.41,52.6
+2020-05-17 11:00:00,9.6,573.0,159.59,437.0,4.55,47.05
+2020-05-17 12:00:00,10.33,620.0,255.56,409.0,4.55,47.2
+2020-05-17 13:00:00,10.57,563.0,248.49,374.0,4.14,45.55
+2020-05-17 14:00:00,10.92,502.0,288.76,311.0,3.93,43.95
+2020-05-17 15:00:00,11.01,423.0,360.78,230.0,3.45,45.7
+2020-05-17 16:00:00,10.97,223.0,115.46,178.0,2.9,45.7
+2020-05-17 17:00:00,10.85,118.0,84.84,98.0,2.28,49.2
+2020-05-17 18:00:00,10.15,41.0,155.92,28.0,1.38,57.15
+2020-05-17 19:00:00,8.44,0.0,-0.0,0.0,1.17,68.7
+2020-05-17 20:00:00,9.33,0.0,-0.0,0.0,0.21,54.8
+2020-05-17 21:00:00,7.9,0.0,-0.0,0.0,1.1,56.7
+2020-05-17 22:00:00,4.35,0.0,-0.0,0.0,2.0,73.45
+2020-05-17 23:00:00,3.21,0.0,-0.0,0.0,2.14,79.1
+2020-05-18 00:00:00,2.73,0.0,-0.0,0.0,2.21,82.15
+2020-05-18 01:00:00,2.54,0.0,-0.0,0.0,2.34,79.0
+2020-05-18 02:00:00,2.65,0.0,-0.0,0.0,2.55,79.0
+2020-05-18 03:00:00,2.77,0.0,-0.0,0.0,2.62,79.0
+2020-05-18 04:00:00,3.37,75.0,187.03,50.0,2.69,73.3
+2020-05-18 05:00:00,5.74,213.0,358.28,110.0,2.9,68.2
+2020-05-18 06:00:00,8.01,355.0,420.8,170.0,3.38,63.6
+2020-05-18 07:00:00,9.01,447.0,324.28,259.0,3.79,61.45
+2020-05-18 08:00:00,10.35,606.0,472.58,276.0,4.21,55.05
+2020-05-18 09:00:00,11.41,539.0,182.94,395.0,4.34,49.45
+2020-05-18 10:00:00,12.53,578.0,180.88,426.0,4.28,46.1
+2020-05-18 11:00:00,13.29,687.0,336.01,400.0,4.34,44.5
+2020-05-18 12:00:00,14.04,572.0,184.85,419.0,4.55,41.5
+2020-05-18 13:00:00,14.55,430.0,76.04,372.0,4.48,41.65
+2020-05-18 14:00:00,14.58,441.0,171.75,327.0,4.07,41.65
+2020-05-18 15:00:00,14.27,353.0,180.48,256.0,3.93,44.75
+2020-05-18 16:00:00,14.27,369.0,713.47,89.0,3.45,46.5
+2020-05-18 17:00:00,13.87,147.0,201.14,99.0,2.62,50.0
+2020-05-18 18:00:00,12.74,41.0,150.32,28.0,2.41,51.65
+2020-05-18 19:00:00,11.35,0.0,-0.0,0.0,2.48,57.4
+2020-05-18 20:00:00,10.28,0.0,-0.0,0.0,2.62,59.35
+2020-05-18 21:00:00,9.7,0.0,-0.0,0.0,2.76,59.25
+2020-05-18 22:00:00,9.33,0.0,-0.0,0.0,2.9,59.15
+2020-05-18 23:00:00,9.06,0.0,-0.0,0.0,3.03,59.15
+2020-05-19 00:00:00,8.79,0.0,-0.0,0.0,3.03,63.7
+2020-05-19 01:00:00,8.81,0.0,-0.0,0.0,2.97,66.15
+2020-05-19 02:00:00,8.51,0.0,-0.0,0.0,2.9,66.15
+2020-05-19 03:00:00,8.25,0.0,-0.0,0.0,2.9,68.6
+2020-05-19 04:00:00,8.07,78.0,212.59,49.0,2.76,71.25
+2020-05-19 05:00:00,9.51,219.0,399.97,103.0,2.55,68.9
+2020-05-19 06:00:00,11.84,382.0,563.38,133.0,2.48,66.75
+2020-05-19 07:00:00,14.47,555.0,725.19,133.0,2.62,58.25
+2020-05-19 08:00:00,15.96,692.0,779.65,146.0,2.69,54.45
+2020-05-19 09:00:00,17.79,750.0,665.31,225.0,2.69,52.75
+2020-05-19 10:00:00,19.21,869.0,856.07,148.0,2.76,47.65
+2020-05-19 11:00:00,20.22,895.0,884.29,138.0,2.83,44.6
+2020-05-19 12:00:00,20.96,849.0,840.1,152.0,2.76,43.1
+2020-05-19 13:00:00,21.5,767.0,804.09,152.0,2.62,40.2
+2020-05-19 14:00:00,21.78,654.0,774.77,138.0,2.48,38.9
+2020-05-19 15:00:00,21.77,517.0,740.89,117.0,2.48,38.9
+2020-05-19 16:00:00,21.43,340.0,574.54,113.0,2.48,41.7
+2020-05-19 17:00:00,20.44,190.0,488.64,72.0,2.07,49.7
+2020-05-19 18:00:00,18.59,41.0,122.86,30.0,2.34,54.95
+2020-05-19 19:00:00,17.19,0.0,-0.0,0.0,2.76,54.7
+2020-05-19 20:00:00,15.93,0.0,-0.0,0.0,2.97,56.35
+2020-05-19 21:00:00,15.08,0.0,-0.0,0.0,3.03,54.25
+2020-05-19 22:00:00,14.36,0.0,-0.0,0.0,3.03,56.0
+2020-05-19 23:00:00,13.71,0.0,-0.0,0.0,3.03,58.0
+2020-05-20 00:00:00,13.12,0.0,-0.0,0.0,3.03,60.05
+2020-05-20 01:00:00,12.43,0.0,-0.0,0.0,3.03,62.2
+2020-05-20 02:00:00,11.92,0.0,-0.0,0.0,3.03,62.1
+2020-05-20 03:00:00,11.54,0.0,-0.0,0.0,3.1,64.35
+2020-05-20 04:00:00,11.38,89.0,309.24,46.0,3.03,69.15
+2020-05-20 05:00:00,12.54,240.0,526.58,86.0,2.97,66.95
+2020-05-20 06:00:00,14.67,404.0,655.08,113.0,2.97,64.95
+2020-05-20 07:00:00,17.0,568.0,756.86,126.0,3.59,56.75
+2020-05-20 08:00:00,18.52,707.0,811.66,137.0,3.86,54.95
+2020-05-20 09:00:00,20.02,818.0,858.45,139.0,4.0,51.5
+2020-05-20 10:00:00,21.43,882.0,877.91,141.0,4.0,48.2
+2020-05-20 11:00:00,22.64,908.0,905.69,131.0,4.0,43.65
+2020-05-20 12:00:00,23.62,880.0,907.91,125.0,3.93,42.35
+2020-05-20 13:00:00,24.28,796.0,871.06,128.0,3.93,41.0
+2020-05-20 14:00:00,24.65,676.0,827.59,123.0,3.93,39.7
+2020-05-20 15:00:00,24.68,527.0,761.6,114.0,3.93,39.7
+2020-05-20 16:00:00,24.22,350.0,611.03,107.0,3.38,44.05
+2020-05-20 17:00:00,23.13,122.0,85.96,101.0,3.1,48.7
+2020-05-20 18:00:00,21.38,19.0,0.0,19.0,2.97,53.6
+2020-05-20 19:00:00,19.84,0.0,-0.0,0.0,3.1,53.25
+2020-05-20 20:00:00,18.67,0.0,-0.0,0.0,3.1,54.95
+2020-05-20 21:00:00,17.87,0.0,-0.0,0.0,3.1,56.75
+2020-05-20 22:00:00,17.37,0.0,-0.0,0.0,3.24,54.7
+2020-05-20 23:00:00,17.06,0.0,-0.0,0.0,3.38,54.7
+2020-05-21 00:00:00,16.94,0.0,-0.0,0.0,3.52,56.6
+2020-05-21 01:00:00,16.8,0.0,-0.0,0.0,3.59,56.6
+2020-05-21 02:00:00,16.45,0.0,-0.0,0.0,3.66,58.6
+2020-05-21 03:00:00,16.11,0.0,-0.0,0.0,3.72,60.75
+2020-05-21 04:00:00,15.85,64.0,84.75,52.0,3.72,65.15
+2020-05-21 05:00:00,16.61,207.0,318.87,113.0,3.86,65.35
+2020-05-21 06:00:00,18.14,260.0,127.7,203.0,3.59,65.55
+2020-05-21 07:00:00,19.84,239.0,17.07,229.0,4.76,61.4
+2020-05-21 08:00:00,21.67,272.0,8.52,266.0,4.97,53.75
+2020-05-21 09:00:00,23.6,304.0,7.57,298.0,5.03,48.8
+2020-05-21 10:00:00,25.23,136.0,0.0,136.0,5.66,42.75
+2020-05-21 11:00:00,25.92,127.0,0.0,127.0,6.41,39.95
+2020-05-21 12:00:00,24.77,250.0,0.0,250.0,6.21,45.75
+2020-05-21 13:00:00,26.07,385.0,46.82,349.0,6.97,37.35
+2020-05-21 14:00:00,26.0,371.0,83.54,315.0,6.55,35.9
+2020-05-21 15:00:00,25.8,188.0,5.51,185.0,6.21,35.9
+2020-05-21 16:00:00,25.2,114.0,0.0,114.0,5.38,38.45
+2020-05-21 17:00:00,24.12,86.0,16.19,82.0,4.83,41.0
+2020-05-21 18:00:00,22.79,20.0,0.0,20.0,4.55,43.65
+2020-05-21 19:00:00,21.81,0.0,-0.0,0.0,4.41,44.95
+2020-05-21 20:00:00,21.01,0.0,-0.0,0.0,4.41,46.5
+2020-05-21 21:00:00,20.04,0.0,-0.0,0.0,4.21,51.5
+2020-05-21 22:00:00,18.83,0.0,-0.0,0.0,3.72,61.2
+2020-05-21 23:00:00,17.97,0.0,-0.0,0.0,3.38,65.55
+2020-05-22 00:00:00,17.48,0.0,-0.0,0.0,3.38,67.85
+2020-05-22 01:00:00,17.16,0.0,-0.0,0.0,3.24,70.3
+2020-05-22 02:00:00,16.9,0.0,-0.0,0.0,3.1,72.7
+2020-05-22 03:00:00,16.59,0.0,-0.0,0.0,3.03,72.7
+2020-05-22 04:00:00,16.48,23.0,0.0,23.0,2.9,72.7
+2020-05-22 05:00:00,17.36,142.0,67.33,122.0,2.76,72.8
+2020-05-22 06:00:00,19.12,372.0,508.45,144.0,2.55,70.55
+2020-05-22 07:00:00,21.34,520.0,586.85,175.0,3.38,61.7
+2020-05-22 08:00:00,22.9,664.0,691.3,176.0,3.59,57.9
+2020-05-22 09:00:00,24.18,753.0,685.99,208.0,3.59,50.7
+2020-05-22 10:00:00,24.96,820.0,724.48,206.0,3.59,47.4
+2020-05-22 11:00:00,25.45,315.0,4.64,311.0,3.52,44.3
+2020-05-22 12:00:00,25.55,599.0,239.45,399.0,3.52,42.9
+2020-05-22 13:00:00,25.97,280.0,5.19,276.0,3.66,42.9
+2020-05-22 14:00:00,25.7,540.0,398.54,272.0,3.59,42.9
+2020-05-22 15:00:00,25.53,507.0,700.29,124.0,3.45,45.9
+2020-05-22 16:00:00,25.1,341.0,566.14,113.0,2.28,49.2
+2020-05-22 17:00:00,24.63,90.0,20.02,85.0,1.79,54.45
+2020-05-22 18:00:00,23.25,7.0,0.0,7.0,2.9,60.05
+2020-05-22 19:00:00,22.14,0.0,-0.0,0.0,1.79,57.75
+2020-05-22 20:00:00,20.19,0.0,-0.0,0.0,1.72,68.3
+2020-05-22 21:00:00,19.18,0.0,-0.0,0.0,1.66,70.55
+2020-05-22 22:00:00,19.17,0.0,-0.0,0.0,1.45,68.1
+2020-05-22 23:00:00,18.52,0.0,-0.0,0.0,1.52,70.45
+2020-05-23 00:00:00,17.37,0.0,-0.0,0.0,1.72,75.4
+2020-05-23 01:00:00,16.36,0.0,-0.0,0.0,1.86,77.95
+2020-05-23 02:00:00,15.58,0.0,-0.0,0.0,1.79,80.65
+2020-05-23 03:00:00,14.93,0.0,0.0,0.0,1.79,83.45
+2020-05-23 04:00:00,14.45,85.0,211.8,54.0,1.72,83.45
+2020-05-23 05:00:00,16.2,239.0,491.35,92.0,1.38,83.6
+2020-05-23 06:00:00,20.05,405.0,648.33,113.0,1.38,65.95
+2020-05-23 07:00:00,21.91,568.0,751.23,125.0,1.86,68.6
+2020-05-23 08:00:00,23.4,709.0,816.82,131.0,2.48,62.15
+2020-05-23 09:00:00,24.78,819.0,865.46,130.0,3.17,50.8
+2020-05-23 10:00:00,25.51,645.0,289.71,399.0,3.66,42.75
+2020-05-23 11:00:00,25.76,862.0,786.71,183.0,3.66,39.95
+2020-05-23 12:00:00,26.07,779.0,620.06,260.0,3.59,38.7
+2020-05-23 13:00:00,26.49,641.0,418.02,318.0,3.59,40.1
+2020-05-23 14:00:00,26.66,651.0,745.72,148.0,3.52,38.85
+2020-05-23 15:00:00,26.62,506.0,671.94,137.0,3.52,38.85
+2020-05-23 16:00:00,26.21,343.0,552.87,119.0,3.72,40.1
+2020-05-23 17:00:00,24.68,188.0,416.09,83.0,3.66,47.4
+2020-05-23 18:00:00,23.25,27.0,9.89,26.0,3.38,54.1
+2020-05-23 19:00:00,22.2,0.0,-0.0,0.0,2.48,52.0
+2020-05-23 20:00:00,20.82,0.0,-0.0,0.0,2.28,59.5
+2020-05-23 21:00:00,19.51,0.0,-0.0,0.0,2.28,65.85
+2020-05-23 22:00:00,18.64,0.0,-0.0,0.0,2.55,72.95
+2020-05-23 23:00:00,18.05,0.0,-0.0,0.0,2.55,75.45
+2020-05-24 00:00:00,16.86,0.0,-0.0,0.0,1.86,83.65
+2020-05-24 01:00:00,15.88,0.0,-0.0,0.0,1.86,86.5
+2020-05-24 02:00:00,15.12,0.0,-0.0,0.0,2.14,89.55
+2020-05-24 03:00:00,14.81,0.0,0.0,0.0,2.28,92.7
+2020-05-24 04:00:00,14.93,80.0,161.51,56.0,2.48,92.7
+2020-05-24 05:00:00,15.67,208.0,288.83,121.0,2.55,80.65
+2020-05-24 06:00:00,16.53,399.0,603.64,126.0,3.1,67.75
+2020-05-24 07:00:00,17.2,496.0,464.97,221.0,3.17,75.4
+2020-05-24 08:00:00,18.37,653.0,613.33,218.0,3.38,72.9
+2020-05-24 09:00:00,19.68,687.0,467.61,314.0,3.66,63.6
+2020-05-24 10:00:00,20.73,749.0,499.59,324.0,3.93,57.45
+2020-05-24 11:00:00,21.54,847.0,725.11,220.0,4.14,48.3
+2020-05-24 12:00:00,22.04,862.0,852.49,147.0,4.34,41.95
+2020-05-24 13:00:00,22.42,776.0,806.94,151.0,4.55,40.5
+2020-05-24 14:00:00,22.53,668.0,787.86,135.0,4.62,37.75
+2020-05-24 15:00:00,22.4,500.0,629.38,153.0,4.69,39.05
+2020-05-24 16:00:00,21.9,324.0,436.76,146.0,4.62,38.9
+2020-05-24 17:00:00,21.16,175.0,305.97,97.0,3.93,41.7
+2020-05-24 18:00:00,19.96,39.0,48.13,34.0,3.79,42.85
+2020-05-24 19:00:00,18.69,0.0,-0.0,0.0,3.24,42.6
+2020-05-24 20:00:00,17.49,0.0,-0.0,0.0,3.17,43.9
+2020-05-24 21:00:00,16.36,0.0,-0.0,0.0,2.83,43.65
+2020-05-24 22:00:00,15.22,0.0,-0.0,0.0,2.55,45.05
+2020-05-24 23:00:00,13.99,0.0,-0.0,0.0,2.28,48.25
+2020-05-25 00:00:00,12.44,0.0,-0.0,0.0,2.0,55.65
+2020-05-25 01:00:00,11.09,0.0,-0.0,0.0,1.93,61.85
+2020-05-25 02:00:00,9.98,0.0,-0.0,0.0,1.93,66.45
+2020-05-25 03:00:00,9.12,0.0,0.0,0.0,2.0,71.4
+2020-05-25 04:00:00,9.01,52.0,19.9,49.0,1.86,76.95
+2020-05-25 05:00:00,11.21,163.0,102.26,132.0,1.72,71.75
+2020-05-25 06:00:00,13.02,428.0,709.19,106.0,2.34,62.3
+2020-05-25 07:00:00,14.1,589.0,792.48,119.0,2.62,62.55
+2020-05-25 08:00:00,15.55,730.0,846.94,128.0,2.83,58.45
+2020-05-25 09:00:00,16.95,833.0,870.9,137.0,3.24,56.6
+2020-05-25 10:00:00,18.02,898.0,889.47,140.0,3.52,51.0
+2020-05-25 11:00:00,18.81,925.0,917.75,130.0,3.59,47.55
+2020-05-25 12:00:00,19.43,879.0,872.24,146.0,3.52,44.3
+2020-05-25 13:00:00,19.99,796.0,837.29,146.0,3.59,41.45
+2020-05-25 14:00:00,20.31,683.0,809.19,134.0,3.66,39.95
+2020-05-25 15:00:00,20.39,539.0,758.84,119.0,3.72,38.5
+2020-05-25 16:00:00,20.14,371.0,648.98,105.0,3.66,37.1
+2020-05-25 17:00:00,19.63,211.0,536.05,73.0,2.97,39.8
+2020-05-25 18:00:00,18.59,58.0,197.06,37.0,2.41,44.2
+2020-05-25 19:00:00,16.96,0.0,-0.0,0.0,2.0,43.9
+2020-05-25 20:00:00,15.36,0.0,-0.0,0.0,2.07,50.35
+2020-05-25 21:00:00,13.65,0.0,-0.0,0.0,2.0,60.2
+2020-05-25 22:00:00,12.65,0.0,-0.0,0.0,1.79,64.55
+2020-05-25 23:00:00,11.7,0.0,-0.0,0.0,1.86,64.35
+2020-05-26 00:00:00,11.03,0.0,-0.0,0.0,1.86,64.25
+2020-05-26 01:00:00,10.83,0.0,-0.0,0.0,1.72,66.55
+2020-05-26 02:00:00,10.75,0.0,-0.0,0.0,1.52,64.1
+2020-05-26 03:00:00,10.57,0.0,0.0,0.0,1.45,64.1
+2020-05-26 04:00:00,10.08,104.0,353.5,50.0,1.45,69.0
+2020-05-26 05:00:00,12.08,255.0,554.08,86.0,0.83,66.85
+2020-05-26 06:00:00,15.14,421.0,680.24,111.0,0.9,56.25
+2020-05-26 07:00:00,16.79,570.0,728.19,137.0,1.52,56.6
+2020-05-26 08:00:00,18.17,721.0,825.54,133.0,2.21,49.15
+2020-05-26 09:00:00,19.04,767.0,674.5,227.0,2.9,42.7
+2020-05-26 10:00:00,19.65,863.0,798.94,181.0,3.17,42.85
+2020-05-26 11:00:00,20.21,919.0,908.11,131.0,3.24,41.45
+2020-05-26 12:00:00,20.59,0.0,0.0,0.0,2.97,40.1
+2020-05-26 13:00:00,20.96,761.0,728.75,194.0,2.76,40.1
+2020-05-26 14:00:00,21.18,439.0,157.27,332.0,2.62,38.75
+2020-05-26 15:00:00,21.05,461.0,450.0,211.0,2.83,37.35
+2020-05-26 16:00:00,20.79,311.0,354.25,165.0,2.76,38.65
+2020-05-26 17:00:00,20.27,205.0,488.66,78.0,1.79,43.0
+2020-05-26 18:00:00,19.18,67.0,293.09,35.0,1.31,53.15
+2020-05-26 19:00:00,17.44,0.0,-0.0,0.0,2.0,49.05
+2020-05-26 20:00:00,16.3,0.0,-0.0,0.0,2.07,50.6
+2020-05-26 21:00:00,15.6,0.0,-0.0,0.0,2.34,52.4
+2020-05-26 22:00:00,14.8,0.0,-0.0,0.0,2.21,58.25
+2020-05-26 23:00:00,13.88,0.0,-0.0,0.0,1.79,69.65
+2020-05-27 00:00:00,13.69,0.0,-0.0,0.0,1.38,69.65
+2020-05-27 01:00:00,14.07,0.0,-0.0,0.0,1.1,64.85
+2020-05-27 02:00:00,14.88,0.0,-0.0,0.0,0.55,60.4
+2020-05-27 03:00:00,13.37,0.0,0.0,0.0,1.1,69.55
+2020-05-27 04:00:00,12.17,58.0,32.32,53.0,1.24,80.2
+2020-05-27 05:00:00,13.12,239.0,443.35,103.0,0.83,86.3
+2020-05-27 06:00:00,14.96,408.0,627.57,121.0,0.83,69.9
+2020-05-27 07:00:00,17.12,572.0,738.13,132.0,0.69,63.2
+2020-05-27 08:00:00,18.63,708.0,791.71,143.0,1.31,56.95
+2020-05-27 09:00:00,19.82,736.0,591.06,262.0,2.0,47.8
+2020-05-27 10:00:00,20.33,825.0,693.57,232.0,2.14,43.0
+2020-05-27 11:00:00,20.68,697.0,352.06,391.0,2.07,41.55
+2020-05-27 12:00:00,21.05,454.0,62.83,401.0,2.07,40.2
+2020-05-27 13:00:00,21.09,114.0,0.0,114.0,2.14,40.2
+2020-05-27 14:00:00,21.03,600.0,533.57,236.0,2.21,40.2
+2020-05-27 15:00:00,20.86,127.0,0.0,127.0,2.14,41.55
+2020-05-27 16:00:00,20.74,171.0,24.13,161.0,2.14,41.55
+2020-05-27 17:00:00,20.05,103.0,26.69,96.0,1.59,46.2
+2020-05-27 18:00:00,19.16,35.0,17.9,33.0,1.31,55.05
+2020-05-27 19:00:00,17.39,0.0,-0.0,0.0,1.24,67.85
+2020-05-27 20:00:00,17.18,0.0,-0.0,0.0,1.03,56.75
+2020-05-27 21:00:00,17.78,0.0,-0.0,0.0,0.83,52.75
+2020-05-27 22:00:00,17.58,0.0,-0.0,0.0,0.69,50.85
+2020-05-27 23:00:00,17.3,0.0,-0.0,0.0,0.9,50.85
+2020-05-28 00:00:00,15.11,0.0,-0.0,0.0,1.24,60.5
+2020-05-28 01:00:00,13.93,0.0,-0.0,0.0,1.45,67.25
+2020-05-28 02:00:00,13.16,0.0,-0.0,0.0,1.52,72.1
+2020-05-28 03:00:00,12.89,0.0,0.0,0.0,1.45,77.45
+2020-05-28 04:00:00,12.93,51.0,12.78,49.0,1.38,77.5
+2020-05-28 05:00:00,14.18,186.0,171.85,133.0,1.03,80.45
+2020-05-28 06:00:00,17.09,103.0,0.0,103.0,1.03,60.95
+2020-05-28 07:00:00,17.43,126.0,0.0,126.0,1.93,67.85
+2020-05-28 08:00:00,18.23,393.0,75.53,339.0,1.86,67.95
+2020-05-28 09:00:00,18.45,484.0,110.8,395.0,2.0,67.95
+2020-05-28 10:00:00,19.26,754.0,499.83,326.0,2.07,63.5
+2020-05-28 11:00:00,19.51,861.0,748.97,209.0,1.86,61.4
+2020-05-28 12:00:00,19.83,760.0,542.04,302.0,1.79,59.25
+2020-05-28 13:00:00,20.11,575.0,261.09,371.0,2.21,55.3
+2020-05-28 14:00:00,20.18,599.0,523.4,241.0,2.41,51.5
+2020-05-28 15:00:00,20.65,496.0,579.03,172.0,2.41,48.05
+2020-05-28 16:00:00,20.57,339.0,468.17,144.0,2.34,44.7
+2020-05-28 17:00:00,20.47,199.0,415.7,89.0,1.93,44.6
+2020-05-28 18:00:00,19.49,62.0,192.64,40.0,1.1,55.2
+2020-05-28 19:00:00,20.3,0.0,-0.0,0.0,0.21,41.45
+2020-05-28 20:00:00,19.52,0.0,-0.0,0.0,0.69,42.85
+2020-05-28 21:00:00,16.37,0.0,-0.0,0.0,1.45,54.45
+2020-05-28 22:00:00,13.79,0.0,-0.0,0.0,1.79,67.15
+2020-05-28 23:00:00,12.52,0.0,-0.0,0.0,1.79,74.7
+2020-05-29 00:00:00,11.53,0.0,-0.0,0.0,1.79,80.15
+2020-05-29 01:00:00,10.8,0.0,-0.0,0.0,1.79,86.05
+2020-05-29 02:00:00,10.52,0.0,-0.0,0.0,1.79,86.05
+2020-05-29 03:00:00,10.15,0.0,0.0,0.0,1.93,89.2
+2020-05-29 04:00:00,10.57,87.0,164.32,61.0,1.86,86.05
+2020-05-29 05:00:00,13.34,173.0,125.82,134.0,1.59,83.25
+2020-05-29 06:00:00,17.7,273.0,132.54,212.0,1.93,60.95
+2020-05-29 07:00:00,18.46,327.0,80.16,279.0,3.24,63.3
+2020-05-29 08:00:00,19.28,707.0,781.92,147.0,3.17,61.3
+2020-05-29 09:00:00,20.36,797.0,771.96,176.0,3.59,57.3
+2020-05-29 10:00:00,21.27,791.0,592.4,283.0,4.28,48.2
+2020-05-29 11:00:00,21.73,727.0,408.33,371.0,4.41,43.4
+2020-05-29 12:00:00,22.18,693.0,385.17,367.0,4.9,40.5
+2020-05-29 13:00:00,22.42,583.0,274.62,368.0,5.45,39.05
+2020-05-29 14:00:00,21.54,541.0,357.29,296.0,4.69,43.4
+2020-05-29 15:00:00,21.47,510.0,632.27,155.0,4.69,44.85
+2020-05-29 16:00:00,21.25,302.0,303.38,175.0,4.62,43.25
+2020-05-29 17:00:00,20.54,166.0,209.83,110.0,4.0,43.1
+2020-05-29 18:00:00,19.4,44.0,42.88,39.0,3.38,42.7
+2020-05-29 19:00:00,17.92,0.0,-0.0,0.0,3.03,47.3
+2020-05-29 20:00:00,16.8,0.0,-0.0,0.0,2.55,45.45
+2020-05-29 21:00:00,15.56,0.0,-0.0,0.0,2.28,46.9
+2020-05-29 22:00:00,14.47,0.0,-0.0,0.0,2.21,50.25
+2020-05-29 23:00:00,13.26,0.0,-0.0,0.0,2.0,57.9
+2020-05-30 00:00:00,12.03,0.0,-0.0,0.0,1.79,64.45
+2020-05-30 01:00:00,10.96,0.0,-0.0,0.0,1.72,69.15
+2020-05-30 02:00:00,10.25,0.0,-0.0,0.0,1.66,74.3
+2020-05-30 03:00:00,9.55,0.0,0.0,0.0,1.72,77.0
+2020-05-30 04:00:00,9.48,93.0,200.19,61.0,1.59,79.9
+2020-05-30 05:00:00,11.74,240.0,423.87,108.0,1.31,77.3
+2020-05-30 06:00:00,14.52,291.0,171.16,212.0,2.21,58.25
+2020-05-30 07:00:00,16.1,531.0,563.33,193.0,3.45,56.5
+2020-05-30 08:00:00,17.18,527.0,267.65,335.0,4.21,49.05
+2020-05-30 09:00:00,17.95,473.0,98.07,394.0,4.41,49.05
+2020-05-30 10:00:00,18.79,719.0,416.91,361.0,4.69,49.3
+2020-05-30 11:00:00,19.45,877.0,794.88,183.0,5.45,47.65
+2020-05-30 12:00:00,19.86,847.0,786.79,180.0,5.86,46.1
+2020-05-30 13:00:00,19.54,601.0,307.24,360.0,5.59,46.1
+2020-05-30 14:00:00,19.52,486.0,234.21,325.0,4.97,46.1
+2020-05-30 15:00:00,18.83,539.0,740.24,122.0,4.55,49.3
+2020-05-30 16:00:00,18.61,339.0,451.68,149.0,4.48,49.3
+2020-05-30 17:00:00,18.09,211.0,475.7,83.0,3.86,51.0
+2020-05-30 18:00:00,17.18,63.0,176.54,42.0,2.97,52.75
+2020-05-30 19:00:00,15.48,0.0,-0.0,0.0,2.62,58.45
+2020-05-30 20:00:00,14.43,0.0,-0.0,0.0,2.0,67.25
+2020-05-30 21:00:00,13.57,0.0,-0.0,0.0,1.38,69.65
+2020-05-30 22:00:00,12.31,0.0,-0.0,0.0,1.24,80.2
+2020-05-30 23:00:00,11.47,0.0,-0.0,0.0,1.31,83.1
+2020-05-31 00:00:00,10.81,0.0,-0.0,0.0,1.38,86.05
+2020-05-31 01:00:00,10.42,0.0,-0.0,0.0,1.45,86.05
+2020-05-31 02:00:00,9.82,0.0,-0.0,0.0,1.52,92.45
+2020-05-31 03:00:00,9.56,0.0,0.0,0.0,1.59,89.15
+2020-05-31 04:00:00,10.23,13.0,0.0,13.0,1.38,89.2
+2020-05-31 05:00:00,12.1,34.0,0.0,34.0,0.83,86.2
+2020-05-31 06:00:00,14.51,240.0,75.63,205.0,0.97,69.85
+2020-05-31 07:00:00,15.35,368.0,139.74,284.0,1.17,77.8
+2020-05-31 08:00:00,17.27,182.0,0.0,182.0,2.07,67.85
+2020-05-31 09:00:00,18.35,279.0,2.48,277.0,3.59,63.3
+2020-05-31 10:00:00,18.58,419.0,38.38,386.0,4.0,63.4
+2020-05-31 11:00:00,19.04,450.0,50.33,406.0,3.72,63.5
+2020-05-31 12:00:00,19.51,514.0,115.42,416.0,3.38,63.6
+2020-05-31 13:00:00,20.39,449.0,91.62,377.0,3.31,63.7
+2020-05-31 14:00:00,20.66,100.0,0.0,100.0,2.9,61.6
+2020-05-31 15:00:00,20.48,190.0,3.54,188.0,2.14,61.5
+2020-05-31 16:00:00,15.93,56.0,0.0,56.0,1.72,81.06
+2020-05-31 17:00:00,15.97,59.0,0.0,59.0,1.73,82.32
+2020-05-31 18:00:00,16.02,20.0,0.0,20.0,1.74,83.59
+2020-05-31 19:00:00,16.07,0.0,-0.0,0.0,1.75,84.86
+2020-05-31 20:00:00,16.12,0.0,-0.0,0.0,1.76,86.12
+2020-05-31 21:00:00,16.17,0.0,-0.0,0.0,1.77,87.39
+2020-05-31 22:00:00,16.22,0.0,-0.0,0.0,1.78,88.66
+2020-05-31 23:00:00,16.27,0.0,-0.0,0.0,1.79,89.92
+2020-06-01 00:00:00,16.31,0.0,-0.0,0.0,1.8,91.19
+2020-06-01 01:00:00,16.36,0.0,-0.0,0.0,1.81,92.46
+2020-06-01 02:00:00,16.41,0.0,-0.0,0.0,1.82,93.72
+2020-06-01 03:00:00,16.46,0.0,0.0,0.0,1.83,94.99
+2020-06-01 04:00:00,16.51,32.0,0.0,32.0,1.85,96.26
+2020-06-01 05:00:00,16.56,176.0,136.92,133.0,1.86,97.52
+2020-06-01 06:00:00,16.61,326.0,284.54,194.0,1.87,98.79
+2020-06-01 07:00:00,16.66,460.0,353.71,247.0,1.88,100.0
+2020-06-01 08:00:00,19.94,616.0,507.35,251.0,2.14,86.85
+2020-06-01 09:00:00,20.99,641.0,370.21,342.0,1.93,78.55
+2020-06-01 10:00:00,20.94,643.0,286.92,396.0,1.52,81.2
+2020-06-01 11:00:00,21.09,687.0,346.13,384.0,1.03,78.55
+2020-06-01 12:00:00,22.1,716.0,455.13,329.0,1.03,76.1
+2020-06-01 13:00:00,22.95,705.0,580.48,248.0,0.9,71.15
+2020-06-01 14:00:00,23.35,436.0,159.28,326.0,0.76,71.25
+2020-06-01 15:00:00,23.67,354.0,165.82,260.0,0.97,68.95
+2020-06-01 16:00:00,23.64,50.0,0.0,50.0,1.1,68.95
+2020-06-01 17:00:00,23.27,22.0,0.0,22.0,1.03,71.25
+2020-06-01 18:00:00,21.4,33.0,8.1,32.0,1.86,81.3
+2020-06-01 19:00:00,20.9,0.0,-0.0,0.0,1.52,81.2
+2020-06-01 20:00:00,19.62,0.0,-0.0,0.0,1.38,86.85
+2020-06-01 21:00:00,18.39,0.0,-0.0,0.0,1.66,92.85
+2020-06-01 22:00:00,17.62,0.0,-0.0,0.0,1.86,92.85
+2020-06-01 23:00:00,17.08,0.0,-0.0,0.0,1.79,89.7
+2020-06-02 00:00:00,16.39,0.0,-0.0,0.0,1.79,92.8
+2020-06-02 01:00:00,16.06,0.0,-0.0,0.0,1.79,92.8
+2020-06-02 02:00:00,15.49,0.0,-0.0,0.0,1.93,92.75
+2020-06-02 03:00:00,15.17,0.0,0.0,0.0,2.07,96.0
+2020-06-02 04:00:00,15.63,64.0,36.56,58.0,2.07,92.75
+2020-06-02 05:00:00,17.71,221.0,314.08,122.0,1.93,86.65
+2020-06-02 06:00:00,19.89,388.0,511.87,150.0,2.07,75.7
+2020-06-02 07:00:00,21.58,552.0,654.89,157.0,2.21,64.0
+2020-06-02 08:00:00,22.83,690.0,731.58,163.0,2.41,57.9
+2020-06-02 09:00:00,24.01,800.0,792.74,159.0,2.48,54.2
+2020-06-02 10:00:00,24.98,872.0,834.26,153.0,2.62,50.8
+2020-06-02 11:00:00,25.79,884.0,827.17,159.0,2.62,47.65
+2020-06-02 12:00:00,26.35,873.0,864.35,137.0,2.62,46.15
+2020-06-02 13:00:00,26.63,780.0,795.05,153.0,2.69,44.7
+2020-06-02 14:00:00,26.79,584.0,476.79,254.0,2.69,43.15
+2020-06-02 15:00:00,26.75,530.0,705.28,129.0,2.76,43.15
+2020-06-02 16:00:00,26.34,371.0,607.42,112.0,3.03,46.15
+2020-06-02 17:00:00,25.04,214.0,472.25,84.0,2.34,52.75
+2020-06-02 18:00:00,23.67,69.0,199.17,44.0,2.14,60.15
+2020-06-02 19:00:00,22.32,0.0,-0.0,0.0,2.34,61.95
+2020-06-02 20:00:00,20.84,0.0,-0.0,0.0,2.28,68.4
+2020-06-02 21:00:00,19.75,0.0,-0.0,0.0,2.28,73.15
+2020-06-02 22:00:00,18.88,0.0,-0.0,0.0,2.48,78.25
+2020-06-02 23:00:00,18.42,0.0,-0.0,0.0,2.62,78.15
+2020-06-03 00:00:00,17.93,0.0,-0.0,0.0,2.55,78.1
+2020-06-03 01:00:00,17.24,0.0,-0.0,0.0,2.48,75.4
+2020-06-03 02:00:00,16.65,0.0,-0.0,0.0,2.48,78.0
+2020-06-03 03:00:00,16.16,0.0,0.0,0.0,2.41,77.95
+2020-06-03 04:00:00,16.22,104.0,272.23,59.0,2.34,80.75
+2020-06-03 05:00:00,17.87,249.0,477.43,98.0,2.21,80.85
+2020-06-03 06:00:00,20.15,403.0,588.08,129.0,2.34,70.7
+2020-06-03 07:00:00,21.58,562.0,700.29,139.0,2.83,64.0
+2020-06-03 08:00:00,22.67,699.0,763.99,148.0,2.48,59.95
+2020-06-03 09:00:00,23.77,793.0,774.59,166.0,2.14,58.1
+2020-06-03 10:00:00,24.73,676.0,339.61,383.0,2.07,56.35
+2020-06-03 11:00:00,25.23,228.0,0.0,228.0,2.21,52.75
+2020-06-03 12:00:00,25.84,198.0,0.0,198.0,2.28,51.05
+2020-06-03 13:00:00,25.66,142.0,0.0,142.0,1.52,52.85
+2020-06-03 14:00:00,23.5,137.0,0.0,137.0,1.17,66.55
+2020-06-03 15:00:00,22.1,249.0,28.06,233.0,1.59,76.1
+2020-06-03 16:00:00,21.27,288.0,242.89,184.0,1.03,84.05
+2020-06-03 17:00:00,20.91,105.0,21.64,99.0,1.1,86.9
+2020-06-03 18:00:00,20.34,76.0,258.69,43.0,1.38,92.95
+2020-06-03 19:00:00,18.42,0.0,-0.0,0.0,1.86,96.05
+2020-06-03 20:00:00,17.71,0.0,-0.0,0.0,1.1,96.05
+2020-06-03 21:00:00,17.3,0.0,-0.0,0.0,0.69,96.05
+2020-06-03 22:00:00,16.91,0.0,-0.0,0.0,0.9,96.05
+2020-06-03 23:00:00,16.49,0.0,-0.0,0.0,0.9,96.05
+2020-06-04 00:00:00,16.04,0.0,-0.0,0.0,1.1,96.05
+2020-06-04 01:00:00,15.88,0.0,-0.0,0.0,1.03,96.0
+2020-06-04 02:00:00,16.11,0.0,-0.0,0.0,0.76,96.05
+2020-06-04 03:00:00,16.07,0.0,0.0,0.0,0.62,96.05
+2020-06-04 04:00:00,16.37,12.0,0.0,12.0,0.62,99.4
+2020-06-04 05:00:00,16.5,34.0,0.0,34.0,0.9,96.05
+2020-06-04 06:00:00,16.85,87.0,0.0,87.0,1.59,96.05
+2020-06-04 07:00:00,16.97,146.0,0.0,146.0,1.59,96.05
+2020-06-04 08:00:00,17.58,276.0,8.31,270.0,1.93,96.05
+2020-06-04 09:00:00,18.07,469.0,98.73,389.0,2.48,89.75
+2020-06-04 10:00:00,18.81,511.0,105.37,420.0,3.03,83.8
+2020-06-04 11:00:00,19.8,544.0,128.64,431.0,3.79,75.7
+2020-06-04 12:00:00,20.92,622.0,258.86,401.0,3.72,68.4
+2020-06-04 13:00:00,21.73,368.0,31.6,343.0,3.86,57.65
+2020-06-04 14:00:00,21.97,394.0,96.4,327.0,3.52,55.65
+2020-06-04 15:00:00,22.34,287.0,59.46,253.0,3.52,52.0
+2020-06-04 16:00:00,22.51,178.0,25.59,167.0,3.1,50.3
+2020-06-04 17:00:00,21.76,192.0,315.34,104.0,2.48,55.65
+2020-06-04 18:00:00,20.67,63.0,123.53,47.0,2.07,59.5
+2020-06-04 19:00:00,19.34,0.0,-0.0,0.0,2.0,65.75
+2020-06-04 20:00:00,18.25,0.0,-0.0,0.0,2.28,65.55
+2020-06-04 21:00:00,17.75,0.0,-0.0,0.0,3.17,60.95
+2020-06-04 22:00:00,17.28,0.0,-0.0,0.0,3.59,54.7
+2020-06-04 23:00:00,16.52,0.0,-0.0,0.0,3.31,54.6
+2020-06-05 00:00:00,15.69,0.0,-0.0,0.0,2.9,58.45
+2020-06-05 01:00:00,14.94,0.0,-0.0,0.0,2.69,60.5
+2020-06-05 02:00:00,14.25,0.0,-0.0,0.0,2.48,64.85
+2020-06-05 03:00:00,13.61,0.0,0.0,0.0,2.48,69.65
+2020-06-05 04:00:00,13.47,117.0,364.35,56.0,2.48,72.2
+2020-06-05 05:00:00,14.47,267.0,550.08,92.0,2.41,72.4
+2020-06-05 06:00:00,15.86,426.0,652.3,121.0,3.17,67.55
+2020-06-05 07:00:00,17.05,578.0,713.38,146.0,3.45,67.85
+2020-06-05 08:00:00,18.36,720.0,791.48,148.0,3.79,67.95
+2020-06-05 09:00:00,19.34,820.0,810.13,163.0,4.41,61.3
+2020-06-05 10:00:00,19.81,884.0,828.3,168.0,4.62,57.2
+2020-06-05 11:00:00,20.25,906.0,847.22,161.0,4.55,53.35
+2020-06-05 12:00:00,20.4,886.0,862.22,149.0,4.55,51.5
+2020-06-05 13:00:00,20.58,806.0,827.92,150.0,4.55,48.05
+2020-06-05 14:00:00,20.77,591.0,456.68,273.0,4.48,46.35
+2020-06-05 15:00:00,20.68,561.0,772.75,118.0,4.34,46.35
+2020-06-05 16:00:00,20.33,394.0,665.02,107.0,4.0,47.9
+2020-06-05 17:00:00,19.89,235.0,555.45,79.0,3.03,51.4
+2020-06-05 18:00:00,18.98,81.0,273.95,45.0,2.55,53.15
+2020-06-05 19:00:00,17.39,0.0,-0.0,0.0,2.62,56.75
+2020-06-05 20:00:00,16.21,0.0,-0.0,0.0,2.34,60.75
+2020-06-05 21:00:00,15.13,0.0,-0.0,0.0,2.34,62.75
+2020-06-05 22:00:00,14.38,0.0,-0.0,0.0,2.55,64.85
+2020-06-05 23:00:00,13.97,0.0,-0.0,0.0,2.55,62.55
+2020-06-06 00:00:00,13.76,0.0,-0.0,0.0,2.41,67.15
+2020-06-06 01:00:00,12.72,0.0,-0.0,0.0,2.07,72.05
+2020-06-06 02:00:00,11.63,0.0,-0.0,0.0,1.93,77.3
+2020-06-06 03:00:00,10.81,1.0,0.0,1.0,2.0,83.0
+2020-06-06 04:00:00,10.95,113.0,326.74,58.0,2.0,83.05
+2020-06-06 05:00:00,13.4,269.0,561.27,90.0,2.0,77.5
+2020-06-06 06:00:00,15.43,432.0,676.95,115.0,2.69,69.9
+2020-06-06 07:00:00,16.76,589.0,755.51,131.0,3.03,72.7
+2020-06-06 08:00:00,18.05,680.0,653.92,207.0,4.14,63.3
+2020-06-06 09:00:00,18.79,641.0,336.35,368.0,4.41,59.05
+2020-06-06 10:00:00,19.48,709.0,380.28,380.0,4.41,53.25
+2020-06-06 11:00:00,19.6,658.0,263.58,426.0,4.07,53.25
+2020-06-06 12:00:00,19.9,604.0,212.68,422.0,3.93,53.25
+2020-06-06 13:00:00,20.22,445.0,78.14,383.0,3.93,51.5
+2020-06-06 14:00:00,20.57,400.0,93.17,335.0,4.14,49.8
+2020-06-06 15:00:00,20.39,491.0,499.37,204.0,3.79,51.5
+2020-06-06 16:00:00,19.88,376.0,577.15,126.0,2.97,57.2
+2020-06-06 17:00:00,19.79,201.0,332.66,107.0,2.69,57.2
+2020-06-06 18:00:00,19.01,63.0,105.09,49.0,2.14,59.15
+2020-06-06 19:00:00,18.19,0.0,-0.0,0.0,2.14,65.55
+2020-06-06 20:00:00,16.82,0.0,-0.0,0.0,1.93,67.75
+2020-06-06 21:00:00,15.57,0.0,-0.0,0.0,1.79,75.15
+2020-06-06 22:00:00,14.4,0.0,-0.0,0.0,1.79,80.45
+2020-06-06 23:00:00,14.18,0.0,-0.0,0.0,1.59,77.65
+2020-06-07 00:00:00,13.39,0.0,-0.0,0.0,1.72,80.35
+2020-06-07 01:00:00,12.61,0.0,-0.0,0.0,1.79,80.3
+2020-06-07 02:00:00,12.15,0.0,-0.0,0.0,1.86,83.15
+2020-06-07 03:00:00,11.68,2.0,0.0,2.0,1.93,83.1
+2020-06-07 04:00:00,12.09,86.0,118.25,66.0,1.72,83.15
+2020-06-07 05:00:00,14.08,272.0,578.83,87.0,1.45,83.4
+2020-06-07 06:00:00,17.58,413.0,592.9,135.0,1.59,70.3
+2020-06-07 07:00:00,19.07,570.0,688.89,152.0,1.52,70.55
+2020-06-07 08:00:00,20.7,711.0,766.69,156.0,2.28,63.8
+2020-06-07 09:00:00,21.72,643.0,342.26,365.0,3.31,55.65
+2020-06-07 10:00:00,22.07,286.0,1.15,285.0,3.72,52.0
+2020-06-07 11:00:00,22.24,307.0,2.27,305.0,3.72,52.0
+2020-06-07 12:00:00,22.54,193.0,0.0,193.0,3.66,48.55
+2020-06-07 13:00:00,22.81,626.0,339.82,356.0,3.45,46.85
+2020-06-07 14:00:00,22.9,555.0,366.31,299.0,3.38,43.65
+2020-06-07 15:00:00,22.77,252.0,26.04,237.0,3.31,43.65
+2020-06-07 16:00:00,22.6,297.0,243.85,191.0,3.31,43.65
+2020-06-07 17:00:00,21.97,188.0,256.85,115.0,2.62,50.05
+2020-06-07 18:00:00,20.64,47.0,29.64,43.0,1.79,57.45
+2020-06-07 19:00:00,18.95,0.0,-0.0,0.0,1.66,65.65
+2020-06-07 20:00:00,18.62,0.0,-0.0,0.0,1.31,59.05
+2020-06-07 21:00:00,18.46,0.0,-0.0,0.0,1.31,56.85
+2020-06-07 22:00:00,18.7,0.0,-0.0,0.0,1.17,53.0
+2020-06-07 23:00:00,19.21,0.0,-0.0,0.0,0.9,51.25
+2020-06-08 00:00:00,18.66,0.0,-0.0,0.0,0.76,53.0
+2020-06-08 01:00:00,18.07,0.0,-0.0,0.0,1.03,52.9
+2020-06-08 02:00:00,17.62,0.0,-0.0,0.0,1.03,56.75
+2020-06-08 03:00:00,17.05,1.0,0.0,1.0,1.1,54.7
+2020-06-08 04:00:00,14.86,88.0,129.53,66.0,1.45,67.35
+2020-06-08 05:00:00,15.42,202.0,202.99,137.0,1.24,75.1
+2020-06-08 06:00:00,18.33,401.0,538.98,148.0,0.83,67.95
+2020-06-08 07:00:00,19.58,580.0,732.8,135.0,1.24,63.6
+2020-06-08 08:00:00,21.01,716.0,785.5,147.0,2.14,57.55
+2020-06-08 09:00:00,21.92,815.0,808.34,158.0,2.55,55.65
+2020-06-08 10:00:00,21.71,854.0,752.5,202.0,3.31,55.65
+2020-06-08 11:00:00,20.82,476.0,63.51,420.0,3.59,59.5
+2020-06-08 12:00:00,21.32,425.0,40.81,390.0,3.72,57.55
+2020-06-08 13:00:00,21.73,275.0,2.51,273.0,3.93,51.9
+2020-06-08 14:00:00,21.85,543.0,338.56,306.0,4.34,50.05
+2020-06-08 15:00:00,21.28,533.0,668.47,147.0,4.0,49.95
+2020-06-08 16:00:00,20.93,311.0,288.9,185.0,3.59,51.65
+2020-06-08 17:00:00,20.36,43.0,0.0,43.0,2.69,57.3
+2020-06-08 18:00:00,19.49,41.0,14.64,39.0,2.14,59.25
+2020-06-08 19:00:00,18.44,0.0,-0.0,0.0,1.59,70.35
+2020-06-08 20:00:00,16.93,0.0,-0.0,0.0,1.45,75.3
+2020-06-08 21:00:00,16.18,0.0,-0.0,0.0,1.45,75.25
+2020-06-08 22:00:00,14.75,0.0,-0.0,0.0,1.72,83.45
+2020-06-08 23:00:00,13.76,0.0,-0.0,0.0,1.79,89.45
+2020-06-09 00:00:00,12.94,0.0,-0.0,0.0,1.72,89.4
+2020-06-09 01:00:00,12.51,0.0,-0.0,0.0,1.72,92.6
+2020-06-09 02:00:00,12.36,0.0,-0.0,0.0,1.66,92.6
+2020-06-09 03:00:00,12.11,1.0,0.0,1.0,1.59,92.6
+2020-06-09 04:00:00,12.83,83.0,99.74,66.0,1.24,92.6
+2020-06-09 05:00:00,15.04,186.0,146.55,139.0,0.76,89.55
+2020-06-09 06:00:00,18.23,401.0,542.74,146.0,0.9,78.15
+2020-06-09 07:00:00,20.19,568.0,692.81,147.0,1.24,68.3
+2020-06-09 08:00:00,21.45,708.0,769.87,150.0,1.66,61.7
+2020-06-09 09:00:00,22.57,811.0,802.95,158.0,1.93,55.9
+2020-06-09 10:00:00,23.49,884.0,844.29,152.0,1.93,52.25
+2020-06-09 11:00:00,24.04,892.0,826.18,163.0,1.79,45.6
+2020-06-09 12:00:00,24.24,840.0,744.46,201.0,1.59,44.05
+2020-06-09 13:00:00,24.69,760.0,696.78,205.0,1.31,41.15
+2020-06-09 14:00:00,24.99,534.0,319.48,310.0,1.17,41.15
+2020-06-09 15:00:00,25.03,549.0,730.95,126.0,1.38,38.45
+2020-06-09 16:00:00,24.82,372.0,550.82,131.0,1.45,39.7
+2020-06-09 17:00:00,23.98,218.0,424.69,96.0,1.1,54.2
+2020-06-09 18:00:00,22.63,69.0,130.3,51.0,1.31,62.05
+2020-06-09 19:00:00,20.89,0.0,0.0,0.0,1.86,61.6
+2020-06-09 20:00:00,18.78,0.0,-0.0,0.0,2.07,68.05
+2020-06-09 21:00:00,17.33,0.0,-0.0,0.0,2.14,70.3
+2020-06-09 22:00:00,16.14,0.0,-0.0,0.0,2.28,72.65
+2020-06-09 23:00:00,15.51,0.0,-0.0,0.0,2.28,72.55
+2020-06-10 00:00:00,14.62,0.0,-0.0,0.0,2.14,75.0
+2020-06-10 01:00:00,14.33,0.0,-0.0,0.0,1.93,77.65
+2020-06-10 02:00:00,13.85,0.0,-0.0,0.0,1.86,80.4
+2020-06-10 03:00:00,13.09,2.0,0.0,2.0,1.86,83.25
+2020-06-10 04:00:00,13.05,118.0,356.82,57.0,1.66,86.3
+2020-06-10 05:00:00,15.41,44.0,0.0,44.0,1.1,86.5
+2020-06-10 06:00:00,19.25,70.0,0.0,70.0,1.24,70.55
+2020-06-10 07:00:00,20.79,585.0,741.78,134.0,1.45,63.8
+2020-06-10 08:00:00,22.54,118.0,0.0,118.0,1.72,55.9
+2020-06-10 09:00:00,23.93,0.0,0.0,0.0,2.0,48.8
+2020-06-10 10:00:00,24.82,839.0,693.96,237.0,2.34,44.15
+2020-06-10 11:00:00,25.36,148.0,0.0,148.0,2.48,41.25
+2020-06-10 12:00:00,25.45,144.0,0.0,144.0,2.48,41.25
+2020-06-10 13:00:00,25.68,814.0,842.71,142.0,2.41,39.95
+2020-06-10 14:00:00,25.63,689.0,771.86,147.0,2.48,39.95
+2020-06-10 15:00:00,25.86,90.0,0.0,90.0,2.69,39.95
+2020-06-10 16:00:00,25.41,390.0,622.08,117.0,2.76,42.75
+2020-06-10 17:00:00,24.52,228.0,474.57,91.0,2.07,50.8
+2020-06-10 18:00:00,23.24,15.0,0.0,15.0,1.86,58.0
+2020-06-10 19:00:00,21.61,0.0,0.0,0.0,1.93,59.7
+2020-06-10 20:00:00,19.73,0.0,-0.0,0.0,2.14,68.2
+2020-06-10 21:00:00,18.41,0.0,-0.0,0.0,2.21,72.9
+2020-06-10 22:00:00,17.46,0.0,-0.0,0.0,2.21,72.8
+2020-06-10 23:00:00,16.38,0.0,-0.0,0.0,2.21,77.95
+2020-06-11 00:00:00,15.94,0.0,-0.0,0.0,2.21,75.25
+2020-06-11 01:00:00,15.36,0.0,-0.0,0.0,2.34,77.8
+2020-06-11 02:00:00,14.83,0.0,-0.0,0.0,2.34,80.55
+2020-06-11 03:00:00,14.23,1.0,0.0,1.0,2.21,86.4
+2020-06-11 04:00:00,14.33,11.0,0.0,11.0,2.0,89.5
+2020-06-11 05:00:00,15.84,44.0,0.0,44.0,2.0,83.55
+2020-06-11 06:00:00,16.37,74.0,0.0,74.0,2.9,75.25
+2020-06-11 07:00:00,16.67,94.0,0.0,94.0,2.97,75.3
+2020-06-11 08:00:00,16.64,150.0,0.0,150.0,3.17,72.7
+2020-06-11 09:00:00,17.32,220.0,0.0,220.0,3.31,67.85
+2020-06-11 10:00:00,17.65,185.0,0.0,185.0,3.59,65.45
+2020-06-11 11:00:00,17.64,442.0,43.01,404.0,3.66,63.2
+2020-06-11 12:00:00,18.47,314.0,4.65,310.0,4.07,59.05
+2020-06-11 13:00:00,18.47,245.0,0.0,245.0,3.93,56.95
+2020-06-11 14:00:00,18.82,248.0,4.27,245.0,4.28,53.0
+2020-06-11 15:00:00,18.88,246.0,22.37,233.0,4.34,49.3
+2020-06-11 16:00:00,18.45,176.0,18.18,168.0,4.48,49.15
+2020-06-11 17:00:00,17.45,84.0,3.45,83.0,4.14,49.05
+2020-06-11 18:00:00,16.66,81.0,205.67,52.0,3.31,50.75
+2020-06-11 19:00:00,15.68,0.0,0.0,0.0,2.55,56.35
+2020-06-11 20:00:00,14.97,0.0,-0.0,0.0,2.48,58.35
+2020-06-11 21:00:00,14.18,0.0,-0.0,0.0,2.48,62.55
+2020-06-11 22:00:00,13.68,0.0,-0.0,0.0,2.55,64.75
+2020-06-11 23:00:00,13.01,0.0,-0.0,0.0,2.41,67.05
+2020-06-12 00:00:00,12.57,0.0,-0.0,0.0,2.34,72.05
+2020-06-12 01:00:00,12.13,0.0,-0.0,0.0,2.34,74.6
+2020-06-12 02:00:00,12.1,0.0,-0.0,0.0,2.41,74.6
+2020-06-12 03:00:00,11.64,1.0,0.0,1.0,2.34,77.3
+2020-06-12 04:00:00,11.99,11.0,0.0,11.0,2.21,77.35
+2020-06-12 05:00:00,12.3,43.0,0.0,43.0,2.69,74.6
+2020-06-12 06:00:00,12.88,140.0,2.12,139.0,2.9,72.05
+2020-06-12 07:00:00,13.35,371.0,133.13,290.0,2.48,74.75
+2020-06-12 08:00:00,14.28,469.0,158.48,354.0,2.76,67.25
+2020-06-12 09:00:00,15.15,610.0,277.55,384.0,2.9,58.35
+2020-06-12 10:00:00,15.87,138.0,0.0,138.0,3.03,54.35
+2020-06-12 11:00:00,16.53,127.0,0.0,127.0,3.03,50.75
+2020-06-12 12:00:00,16.8,149.0,0.0,149.0,3.17,47.15
+2020-06-12 13:00:00,16.83,90.0,0.0,90.0,2.62,47.15
+2020-06-12 14:00:00,16.74,121.0,0.0,121.0,1.93,48.9
+2020-06-12 15:00:00,16.61,110.0,0.0,110.0,1.38,48.9
+2020-06-12 16:00:00,16.27,58.0,0.0,58.0,1.03,52.5
+2020-06-12 17:00:00,15.83,68.0,0.0,68.0,0.97,56.35
+2020-06-12 18:00:00,15.24,41.0,7.03,40.0,1.03,62.75
+2020-06-12 19:00:00,14.27,0.0,0.0,0.0,0.28,72.3
+2020-06-12 20:00:00,13.45,0.0,-0.0,0.0,0.48,80.4
+2020-06-12 21:00:00,13.15,0.0,-0.0,0.0,0.34,80.35
+2020-06-12 22:00:00,12.82,0.0,-0.0,0.0,0.62,86.25
+2020-06-12 23:00:00,12.16,0.0,-0.0,0.0,0.76,89.35
+2020-06-13 00:00:00,11.73,0.0,-0.0,0.0,1.17,92.55
+2020-06-13 01:00:00,11.34,0.0,-0.0,0.0,1.17,95.9
+2020-06-13 02:00:00,11.32,0.0,-0.0,0.0,1.1,95.9
+2020-06-13 03:00:00,11.18,6.0,0.0,6.0,0.83,95.9
+2020-06-13 04:00:00,11.24,16.0,0.0,16.0,0.83,95.9
+2020-06-13 05:00:00,11.3,117.0,12.43,113.0,1.1,99.35
+2020-06-13 06:00:00,11.44,191.0,19.12,182.0,1.86,95.9
+2020-06-13 07:00:00,11.72,194.0,1.64,193.0,4.07,83.1
+2020-06-13 08:00:00,12.04,259.0,4.13,256.0,4.07,86.2
+2020-06-13 09:00:00,11.94,315.0,7.37,309.0,4.28,89.35
+2020-06-13 10:00:00,12.84,391.0,21.87,372.0,4.07,89.4
+2020-06-13 11:00:00,13.49,293.0,1.13,292.0,4.21,80.4
+2020-06-13 12:00:00,14.42,184.0,0.0,184.0,4.21,77.65
+2020-06-13 13:00:00,14.78,355.0,21.26,338.0,4.0,75.0
+2020-06-13 14:00:00,15.12,582.0,421.27,285.0,3.66,69.9
+2020-06-13 15:00:00,15.29,166.0,0.0,166.0,3.52,67.45
+2020-06-13 16:00:00,15.15,375.0,535.73,138.0,3.31,67.45
+2020-06-13 17:00:00,14.56,46.0,0.0,46.0,3.52,64.95
+2020-06-13 18:00:00,13.85,47.0,20.9,44.0,3.03,67.15
+2020-06-13 19:00:00,12.6,0.0,0.0,0.0,2.9,69.45
+2020-06-13 20:00:00,11.74,0.0,-0.0,0.0,2.9,74.55
+2020-06-13 21:00:00,11.09,0.0,-0.0,0.0,2.55,77.2
+2020-06-13 22:00:00,10.4,0.0,-0.0,0.0,2.55,80.05
+2020-06-13 23:00:00,9.88,0.0,-0.0,0.0,2.69,85.95
+2020-06-14 00:00:00,9.4,0.0,-0.0,0.0,2.62,82.9
+2020-06-14 01:00:00,9.11,0.0,-0.0,0.0,2.62,85.95
+2020-06-14 02:00:00,8.71,0.0,-0.0,0.0,2.55,89.1
+2020-06-14 03:00:00,8.46,1.0,0.0,1.0,2.41,89.1
+2020-06-14 04:00:00,8.65,112.0,284.87,63.0,2.14,89.1
+2020-06-14 05:00:00,9.82,255.0,453.6,109.0,2.07,89.15
+2020-06-14 06:00:00,11.14,415.0,582.03,141.0,3.03,77.2
+2020-06-14 07:00:00,12.21,473.0,343.44,264.0,2.28,83.15
+2020-06-14 08:00:00,13.1,432.0,107.46,354.0,2.07,77.5
+2020-06-14 09:00:00,14.09,568.0,203.77,402.0,2.14,72.3
+2020-06-14 10:00:00,14.85,441.0,43.73,403.0,2.55,58.25
+2020-06-14 11:00:00,15.57,573.0,144.65,445.0,2.9,48.65
+2020-06-14 12:00:00,16.2,578.0,170.62,431.0,3.17,45.3
+2020-06-14 13:00:00,16.67,683.0,448.49,324.0,3.17,43.8
+2020-06-14 14:00:00,16.5,414.0,102.01,342.0,2.9,45.45
+2020-06-14 15:00:00,16.56,447.0,328.75,255.0,2.76,45.45
+2020-06-14 16:00:00,16.2,210.0,47.36,189.0,2.34,47.0
+2020-06-14 17:00:00,15.88,225.0,422.41,101.0,1.86,50.5
+2020-06-14 18:00:00,15.24,53.0,34.57,48.0,1.03,58.35
+2020-06-14 19:00:00,13.5,0.0,0.0,0.0,1.17,69.65
+2020-06-14 20:00:00,12.23,0.0,-0.0,0.0,1.31,71.95
+2020-06-14 21:00:00,10.93,0.0,-0.0,0.0,1.45,74.45
+2020-06-14 22:00:00,9.55,0.0,-0.0,0.0,1.72,82.9
+2020-06-14 23:00:00,8.7,0.0,-0.0,0.0,1.79,85.9
+2020-06-15 00:00:00,8.17,0.0,-0.0,0.0,1.72,89.05
+2020-06-15 01:00:00,7.67,0.0,-0.0,0.0,1.72,92.35
+2020-06-15 02:00:00,7.41,0.0,-0.0,0.0,1.66,92.35
+2020-06-15 03:00:00,7.08,6.0,0.0,6.0,1.66,95.8
+2020-06-15 04:00:00,8.02,104.0,226.71,65.0,1.38,92.4
+2020-06-15 05:00:00,10.34,60.0,0.0,60.0,0.97,92.5
+2020-06-15 06:00:00,13.41,202.0,27.62,189.0,1.17,72.2
+2020-06-15 07:00:00,14.41,383.0,152.83,290.0,1.38,69.75
+2020-06-15 08:00:00,15.14,472.0,163.95,353.0,1.79,65.05
+2020-06-15 09:00:00,15.84,622.0,300.72,377.0,2.21,60.65
+2020-06-15 10:00:00,15.96,634.0,246.24,420.0,2.07,62.95
+2020-06-15 11:00:00,16.37,428.0,33.89,398.0,1.59,60.75
+2020-06-15 12:00:00,15.98,742.0,464.03,342.0,1.17,65.25
+2020-06-15 13:00:00,16.44,247.0,0.0,247.0,0.76,67.65
+2020-06-15 14:00:00,16.42,62.0,0.0,62.0,0.62,70.1
+2020-06-15 15:00:00,16.46,524.0,594.98,176.0,0.55,70.2
+2020-06-15 16:00:00,16.14,220.0,60.76,193.0,0.55,72.65
+2020-06-15 17:00:00,14.73,163.0,125.61,126.0,1.31,77.75
+2020-06-15 18:00:00,14.6,42.0,6.86,41.0,1.52,80.55
+2020-06-15 19:00:00,13.07,0.0,0.0,0.0,1.79,83.25
+2020-06-15 20:00:00,12.35,0.0,-0.0,0.0,1.93,89.35
+2020-06-15 21:00:00,12.16,0.0,-0.0,0.0,1.79,89.35
+2020-06-15 22:00:00,11.68,0.0,-0.0,0.0,1.79,89.3
+2020-06-15 23:00:00,11.48,0.0,-0.0,0.0,1.66,89.3
+2020-06-16 00:00:00,11.17,0.0,-0.0,0.0,1.66,92.55
+2020-06-16 01:00:00,10.89,0.0,-0.0,0.0,1.59,92.55
+2020-06-16 02:00:00,10.57,0.0,-0.0,0.0,1.52,95.9
+2020-06-16 03:00:00,10.3,1.0,0.0,1.0,1.45,95.9
+2020-06-16 04:00:00,10.45,11.0,0.0,11.0,1.1,95.9
+2020-06-16 05:00:00,11.91,27.0,0.0,27.0,0.83,92.6
+2020-06-16 06:00:00,12.53,47.0,0.0,47.0,0.83,89.4
+2020-06-16 07:00:00,12.45,143.0,0.0,143.0,0.62,86.25
+2020-06-16 08:00:00,12.67,158.0,0.0,158.0,0.9,86.25
+2020-06-16 09:00:00,13.0,373.0,27.0,351.0,0.97,83.25
+2020-06-16 10:00:00,13.96,457.0,56.37,408.0,0.97,77.65
+2020-06-16 11:00:00,14.83,272.0,0.0,272.0,1.03,75.0
+2020-06-16 12:00:00,15.76,340.0,8.12,333.0,0.9,70.0
+2020-06-16 13:00:00,16.47,403.0,46.16,366.0,0.76,65.35
+2020-06-16 14:00:00,16.5,130.0,0.0,130.0,1.17,65.35
+2020-06-16 15:00:00,16.61,478.0,433.67,224.0,1.31,65.35
+2020-06-16 16:00:00,16.57,297.0,224.59,197.0,1.31,65.35
+2020-06-16 17:00:00,16.13,74.0,0.0,74.0,1.03,65.25
+2020-06-16 18:00:00,15.25,49.0,20.46,46.0,1.52,72.45
+2020-06-16 19:00:00,13.91,0.0,0.0,0.0,1.79,77.6
+2020-06-16 20:00:00,12.84,0.0,-0.0,0.0,1.17,86.25
+2020-06-16 21:00:00,11.48,0.0,-0.0,0.0,1.24,92.55
+2020-06-16 22:00:00,10.72,0.0,-0.0,0.0,1.31,92.5
+2020-06-16 23:00:00,9.91,0.0,-0.0,0.0,1.45,92.5
+2020-06-17 00:00:00,9.19,0.0,-0.0,0.0,1.59,95.85
+2020-06-17 01:00:00,8.99,0.0,-0.0,0.0,1.52,95.85
+2020-06-17 02:00:00,8.61,0.0,-0.0,0.0,1.52,99.4
+2020-06-17 03:00:00,8.15,1.0,0.0,1.0,1.59,99.4
+2020-06-17 04:00:00,8.46,95.0,157.18,68.0,1.45,95.85
+2020-06-17 05:00:00,10.42,239.0,360.82,123.0,1.03,95.9
+2020-06-17 06:00:00,12.99,421.0,616.57,131.0,1.1,80.35
+2020-06-17 07:00:00,13.61,559.0,628.09,177.0,0.76,80.4
+2020-06-17 08:00:00,15.1,719.0,777.23,155.0,1.03,65.05
+2020-06-17 09:00:00,16.23,793.0,711.91,213.0,1.45,54.45
+2020-06-17 10:00:00,16.89,808.0,598.18,288.0,1.38,50.75
+2020-06-17 11:00:00,17.8,821.0,589.36,299.0,0.97,49.05
+2020-06-17 12:00:00,18.13,860.0,763.8,201.0,0.83,44.05
+2020-06-17 13:00:00,18.09,785.0,730.54,199.0,1.45,44.05
+2020-06-17 14:00:00,18.13,605.0,469.01,273.0,2.0,45.7
+2020-06-17 15:00:00,18.07,557.0,716.2,137.0,2.21,45.7
+2020-06-17 16:00:00,18.05,394.0,600.81,126.0,2.21,45.7
+2020-06-17 17:00:00,17.7,244.0,529.77,87.0,1.93,49.05
+2020-06-17 18:00:00,16.93,66.0,74.58,55.0,1.59,56.6
+2020-06-17 19:00:00,16.16,0.0,0.0,0.0,1.52,58.6
+2020-06-17 20:00:00,14.88,0.0,-0.0,0.0,1.45,69.85
+2020-06-17 21:00:00,14.43,0.0,-0.0,0.0,1.38,64.95
+2020-06-17 22:00:00,13.93,0.0,-0.0,0.0,1.45,67.25
+2020-06-17 23:00:00,13.39,0.0,-0.0,0.0,1.59,72.1
+2020-06-18 00:00:00,13.01,0.0,-0.0,0.0,1.59,72.1
+2020-06-18 01:00:00,12.84,0.0,-0.0,0.0,1.59,74.7
+2020-06-18 02:00:00,12.77,0.0,-0.0,0.0,1.52,77.45
+2020-06-18 03:00:00,12.52,1.0,0.0,1.0,1.45,80.3
+2020-06-18 04:00:00,12.53,11.0,0.0,11.0,1.31,83.25
+2020-06-18 05:00:00,13.21,43.0,0.0,43.0,1.03,86.3
+2020-06-18 06:00:00,15.22,190.0,19.15,181.0,0.76,72.45
+2020-06-18 07:00:00,15.16,178.0,0.0,178.0,0.55,83.5
+2020-06-18 08:00:00,16.53,467.0,157.14,353.0,0.41,67.75
+2020-06-18 09:00:00,17.26,412.0,46.65,374.0,0.34,63.2
+2020-06-18 10:00:00,18.03,600.0,197.85,428.0,0.28,61.05
+2020-06-18 11:00:00,18.46,773.0,487.66,341.0,0.14,58.9
+2020-06-18 12:00:00,19.24,180.0,0.0,180.0,0.07,55.05
+2020-06-18 13:00:00,20.12,208.0,0.0,208.0,0.07,51.5
+2020-06-18 14:00:00,20.92,310.0,22.58,294.0,0.34,51.65
+2020-06-18 15:00:00,20.83,538.0,648.97,157.0,0.69,51.65
+2020-06-18 16:00:00,20.82,348.0,393.92,172.0,0.83,53.5
+2020-06-18 17:00:00,20.62,225.0,410.61,103.0,0.9,53.5
+2020-06-18 18:00:00,19.7,77.0,141.64,56.0,1.17,65.85
+2020-06-18 19:00:00,19.26,0.0,0.0,0.0,1.03,70.55
+2020-06-18 20:00:00,19.65,0.0,-0.0,0.0,0.55,59.25
+2020-06-18 21:00:00,18.38,0.0,-0.0,0.0,1.03,65.55
+2020-06-18 22:00:00,15.06,0.0,-0.0,0.0,1.93,80.6
+2020-06-18 23:00:00,13.7,0.0,-0.0,0.0,1.93,89.45
+2020-06-19 00:00:00,12.66,0.0,-0.0,0.0,1.86,92.6
+2020-06-19 01:00:00,11.84,0.0,-0.0,0.0,1.86,95.9
+2020-06-19 02:00:00,11.41,0.0,-0.0,0.0,2.0,95.9
+2020-06-19 03:00:00,11.41,3.0,0.0,3.0,2.14,95.9
+2020-06-19 04:00:00,12.43,14.0,0.0,14.0,2.07,92.6
+2020-06-19 05:00:00,14.99,173.0,109.1,138.0,1.86,89.55
+2020-06-19 06:00:00,17.66,360.0,374.74,184.0,1.93,83.7
+2020-06-19 07:00:00,19.55,518.0,506.92,210.0,1.79,73.15
+2020-06-19 08:00:00,20.9,636.0,533.64,249.0,2.07,68.4
+2020-06-19 09:00:00,22.41,540.0,174.35,398.0,2.9,52.0
+2020-06-19 10:00:00,22.92,424.0,37.96,391.0,3.31,45.25
+2020-06-19 11:00:00,23.2,315.0,3.39,312.0,3.03,43.75
+2020-06-19 12:00:00,23.43,497.0,90.35,419.0,3.03,43.75
+2020-06-19 13:00:00,23.49,315.0,9.96,307.0,2.76,47.0
+2020-06-19 14:00:00,23.86,205.0,0.0,205.0,3.31,45.5
+2020-06-19 15:00:00,23.82,570.0,772.53,116.0,3.66,45.5
+2020-06-19 16:00:00,23.65,403.0,657.06,109.0,3.03,47.15
+2020-06-19 17:00:00,23.08,230.0,446.61,97.0,2.14,54.1
+2020-06-19 18:00:00,21.92,38.0,6.71,37.0,1.79,61.85
+2020-06-19 19:00:00,20.3,0.0,0.0,0.0,2.0,61.5
+2020-06-19 20:00:00,18.56,0.0,-0.0,0.0,2.28,65.65
+2020-06-19 21:00:00,17.45,0.0,-0.0,0.0,2.41,67.85
+2020-06-19 22:00:00,16.48,0.0,-0.0,0.0,2.34,67.75
+2020-06-19 23:00:00,15.82,0.0,-0.0,0.0,2.21,72.55
+2020-06-20 00:00:00,15.49,0.0,-0.0,0.0,2.34,70.0
+2020-06-20 01:00:00,14.91,0.0,-0.0,0.0,2.28,75.0
+2020-06-20 02:00:00,14.39,0.0,-0.0,0.0,2.07,77.65
+2020-06-20 03:00:00,13.7,3.0,0.0,3.0,2.07,80.4
+2020-06-20 04:00:00,14.4,52.0,11.72,50.0,2.34,80.45
+2020-06-20 05:00:00,16.09,27.0,0.0,27.0,3.1,72.65
+2020-06-20 06:00:00,17.05,54.0,0.0,54.0,3.38,72.8
+2020-06-20 07:00:00,16.39,157.0,0.0,157.0,2.69,86.55
+2020-06-20 08:00:00,16.69,352.0,42.77,321.0,3.59,83.65
+2020-06-20 09:00:00,17.36,585.0,243.17,387.0,3.79,80.85
+2020-06-20 10:00:00,18.51,604.0,208.23,423.0,3.72,72.95
+2020-06-20 11:00:00,18.84,659.0,272.0,418.0,3.45,68.05
+2020-06-20 12:00:00,19.92,698.0,378.68,371.0,3.59,61.4
+2020-06-20 13:00:00,20.49,699.0,506.67,292.0,3.52,53.5
+2020-06-20 14:00:00,21.05,571.0,396.13,290.0,3.72,49.95
+2020-06-20 15:00:00,21.12,342.0,115.61,274.0,3.45,48.2
+2020-06-20 16:00:00,20.92,398.0,636.13,113.0,3.38,46.35
+2020-06-20 17:00:00,20.28,162.0,120.64,126.0,2.41,49.7
+2020-06-20 18:00:00,19.4,80.0,160.51,56.0,1.72,57.1
+2020-06-20 19:00:00,18.12,0.0,0.0,0.0,1.59,65.55
+2020-06-20 20:00:00,16.56,0.0,-0.0,0.0,1.66,70.2
+2020-06-20 21:00:00,15.39,0.0,-0.0,0.0,1.79,75.1
+2020-06-20 22:00:00,14.9,0.0,-0.0,0.0,1.59,77.75
+2020-06-20 23:00:00,14.45,0.0,-0.0,0.0,1.52,75.0
+2020-06-21 00:00:00,14.66,0.0,-0.0,0.0,1.31,77.75
+2020-06-21 01:00:00,13.9,0.0,-0.0,0.0,1.38,80.4
+2020-06-21 02:00:00,13.51,0.0,-0.0,0.0,1.38,80.4
+2020-06-21 03:00:00,13.35,1.0,0.0,1.0,1.24,86.3
+2020-06-21 04:00:00,13.21,10.0,0.0,10.0,1.17,89.4
+2020-06-21 05:00:00,14.31,39.0,0.0,39.0,0.83,89.5
+2020-06-21 06:00:00,15.83,83.0,0.0,83.0,0.76,77.85
+2020-06-21 07:00:00,17.2,205.0,3.3,203.0,0.9,72.8
+2020-06-21 08:00:00,16.93,144.0,0.0,144.0,1.38,72.7
+2020-06-21 09:00:00,16.63,152.0,0.0,152.0,1.72,75.3
+2020-06-21 10:00:00,16.26,188.0,0.0,188.0,1.66,77.95
+2020-06-21 11:00:00,16.51,159.0,0.0,159.0,1.38,75.3
+2020-06-21 12:00:00,16.48,416.0,37.05,384.0,1.52,75.3
+2020-06-21 13:00:00,17.08,265.0,1.24,264.0,1.86,72.8
+2020-06-21 14:00:00,17.58,407.0,101.45,335.0,2.34,72.8
+2020-06-21 15:00:00,18.94,303.0,66.25,264.0,3.52,68.05
+2020-06-21 16:00:00,18.76,205.0,44.59,185.0,2.97,65.65
+2020-06-21 17:00:00,18.27,239.0,505.17,88.0,2.28,67.95
+2020-06-21 18:00:00,17.78,97.0,306.65,51.0,1.59,70.3
+2020-06-21 19:00:00,17.02,0.0,0.0,0.0,1.17,75.4
+2020-06-21 20:00:00,17.26,0.0,-0.0,0.0,0.34,70.3
+2020-06-21 21:00:00,15.49,0.0,-0.0,0.0,1.17,77.85
+2020-06-21 22:00:00,13.47,0.0,-0.0,0.0,1.79,89.45
+2020-06-21 23:00:00,12.63,0.0,-0.0,0.0,2.0,92.6
+2020-06-22 00:00:00,12.21,0.0,-0.0,0.0,2.07,92.6
+2020-06-22 01:00:00,12.2,0.0,-0.0,0.0,2.28,92.6
+2020-06-22 02:00:00,12.43,0.0,-0.0,0.0,2.41,89.4
+2020-06-22 03:00:00,12.76,2.0,0.0,2.0,2.55,89.4
+2020-06-22 04:00:00,13.53,118.0,371.61,55.0,2.55,86.35
+2020-06-22 05:00:00,15.53,264.0,548.35,89.0,2.48,80.65
+2020-06-22 06:00:00,18.12,421.0,655.89,114.0,2.9,75.45
+2020-06-22 07:00:00,20.43,575.0,739.06,127.0,3.38,70.7
+2020-06-22 08:00:00,22.17,711.0,794.15,136.0,3.72,64.1
+2020-06-22 09:00:00,23.8,821.0,841.89,136.0,3.93,60.15
+2020-06-22 10:00:00,25.4,873.0,827.51,154.0,4.0,56.5
+2020-06-22 11:00:00,26.69,878.0,798.01,171.0,3.86,53.1
+2020-06-22 12:00:00,27.77,665.0,321.86,387.0,3.66,49.8
+2020-06-22 13:00:00,28.44,746.0,650.71,223.0,3.59,49.8
+2020-06-22 14:00:00,28.46,545.0,338.01,305.0,3.52,49.8
+2020-06-22 15:00:00,28.3,286.0,49.23,257.0,3.03,49.8
+2020-06-22 16:00:00,28.11,386.0,585.83,123.0,2.34,53.35
+2020-06-22 17:00:00,27.47,230.0,451.01,95.0,1.72,58.9
+2020-06-22 18:00:00,26.32,47.0,13.3,45.0,1.86,62.8
+2020-06-22 19:00:00,24.63,0.0,0.0,0.0,2.21,62.45
+2020-06-22 20:00:00,23.04,0.0,-0.0,0.0,2.14,64.3
+2020-06-22 21:00:00,21.76,0.0,-0.0,0.0,2.21,71.0
+2020-06-22 22:00:00,21.02,0.0,-0.0,0.0,2.41,70.9
+2020-06-22 23:00:00,21.72,0.0,-0.0,0.0,3.52,64.0
+2020-06-23 00:00:00,21.51,0.0,-0.0,0.0,2.76,64.0
+2020-06-23 01:00:00,20.67,0.0,-0.0,0.0,2.41,68.4
+2020-06-23 02:00:00,20.16,0.0,-0.0,0.0,2.55,70.7
+2020-06-23 03:00:00,19.85,6.0,0.0,6.0,2.62,73.15
+2020-06-23 04:00:00,19.85,10.0,0.0,10.0,2.48,75.7
+2020-06-23 05:00:00,20.4,194.0,185.29,135.0,3.45,78.45
+2020-06-23 06:00:00,19.44,366.0,408.66,175.0,2.62,89.8
+2020-06-23 07:00:00,19.77,209.0,4.95,206.0,3.31,86.85
+2020-06-23 08:00:00,20.39,481.0,186.59,346.0,3.45,83.95
+2020-06-23 09:00:00,22.23,660.0,394.71,339.0,4.21,71.05
+2020-06-23 10:00:00,23.28,786.0,575.63,286.0,4.76,60.05
+2020-06-23 11:00:00,24.09,887.0,816.17,164.0,5.1,50.7
+2020-06-23 12:00:00,24.35,885.0,864.82,138.0,5.03,44.05
+2020-06-23 13:00:00,24.65,817.0,854.61,130.0,4.97,36.95
+2020-06-23 14:00:00,24.6,605.0,491.36,256.0,4.83,33.15
+2020-06-23 15:00:00,24.13,561.0,744.93,122.0,4.48,31.85
+2020-06-23 16:00:00,23.47,402.0,647.72,111.0,3.93,34.0
+2020-06-23 17:00:00,22.44,247.0,540.61,85.0,3.31,39.05
+2020-06-23 18:00:00,21.11,99.0,318.52,51.0,2.69,44.85
+2020-06-23 19:00:00,19.63,0.0,0.0,0.0,2.41,49.55
+2020-06-23 20:00:00,17.98,0.0,-0.0,0.0,2.07,56.85
+2020-06-23 21:00:00,16.31,0.0,-0.0,0.0,2.0,62.95
+2020-06-23 22:00:00,14.83,0.0,-0.0,0.0,1.93,69.85
+2020-06-23 23:00:00,13.76,0.0,-0.0,0.0,1.79,74.85
+2020-06-24 00:00:00,13.06,0.0,-0.0,0.0,1.72,74.75
+2020-06-24 01:00:00,12.88,0.0,-0.0,0.0,1.52,77.45
+2020-06-24 02:00:00,12.37,0.0,-0.0,0.0,1.45,77.35
+2020-06-24 03:00:00,11.73,1.0,0.0,1.0,1.45,80.15
+2020-06-24 04:00:00,11.75,110.0,303.58,59.0,1.31,83.1
+2020-06-24 05:00:00,13.66,256.0,503.76,96.0,1.17,74.85
+2020-06-24 06:00:00,14.83,412.0,615.05,125.0,1.72,69.85
+2020-06-24 07:00:00,15.82,576.0,734.03,132.0,1.79,72.55
+2020-06-24 08:00:00,16.87,708.0,777.37,146.0,1.66,67.75
+2020-06-24 09:00:00,17.91,817.0,821.85,149.0,1.72,65.45
+2020-06-24 10:00:00,19.09,874.0,818.84,163.0,1.72,59.15
+2020-06-24 11:00:00,20.07,847.0,686.49,239.0,1.38,55.3
+2020-06-24 12:00:00,20.68,854.0,773.4,186.0,1.1,53.5
+2020-06-24 13:00:00,21.56,815.0,840.85,139.0,1.17,50.05
+2020-06-24 14:00:00,21.8,527.0,288.56,322.0,1.59,50.05
+2020-06-24 15:00:00,21.85,385.0,184.89,276.0,2.14,50.05
+2020-06-24 16:00:00,21.63,391.0,591.74,125.0,2.28,50.05
+2020-06-24 17:00:00,21.07,220.0,373.45,108.0,2.0,49.95
+2020-06-24 18:00:00,20.23,81.0,152.42,58.0,1.79,55.3
+2020-06-24 19:00:00,18.68,0.0,0.0,0.0,1.86,56.95
+2020-06-24 20:00:00,17.17,0.0,-0.0,0.0,1.59,60.95
+2020-06-24 21:00:00,15.84,0.0,-0.0,0.0,1.59,70.0
+2020-06-24 22:00:00,15.45,0.0,-0.0,0.0,1.79,65.15
+2020-06-24 23:00:00,15.04,0.0,-0.0,0.0,1.93,65.05
+2020-06-25 00:00:00,14.7,0.0,-0.0,0.0,2.14,62.65
+2020-06-25 01:00:00,14.77,0.0,-0.0,0.0,2.21,60.4
+2020-06-25 02:00:00,14.77,0.0,-0.0,0.0,2.21,58.25
+2020-06-25 03:00:00,14.36,3.0,0.0,3.0,2.14,62.55
+2020-06-25 04:00:00,14.46,27.0,0.0,27.0,2.0,67.35
+2020-06-25 05:00:00,15.88,248.0,479.9,96.0,1.79,67.55
+2020-06-25 06:00:00,18.46,388.0,530.28,141.0,2.07,65.55
+2020-06-25 07:00:00,20.66,410.0,226.77,273.0,2.34,63.8
+2020-06-25 08:00:00,22.7,426.0,116.29,342.0,2.34,59.95
+2020-06-25 09:00:00,24.47,723.0,572.45,258.0,2.48,58.2
+2020-06-25 10:00:00,25.66,675.0,342.19,378.0,2.83,56.6
+2020-06-25 11:00:00,26.41,407.0,28.23,382.0,2.97,56.7
+2020-06-25 12:00:00,26.9,108.0,0.0,108.0,2.76,56.85
+2020-06-25 13:00:00,26.36,475.0,113.19,384.0,2.34,60.7
+2020-06-25 14:00:00,24.59,386.0,80.22,329.0,1.86,69.15
+2020-06-25 15:00:00,22.23,49.0,0.0,49.0,1.66,87.05
+2020-06-25 16:00:00,21.88,63.0,0.0,63.0,2.14,89.95
+2020-06-25 17:00:00,21.74,21.0,0.0,21.0,1.79,89.95
+2020-06-25 18:00:00,21.63,28.0,0.0,28.0,2.34,89.95
+2020-06-25 19:00:00,19.96,0.0,0.0,0.0,2.9,96.1
+2020-06-25 20:00:00,19.53,0.0,-0.0,0.0,3.1,92.9
+2020-06-25 21:00:00,19.2,0.0,-0.0,0.0,2.97,92.9
+2020-06-25 22:00:00,18.98,0.0,-0.0,0.0,2.9,92.9
+2020-06-25 23:00:00,18.78,0.0,-0.0,0.0,2.97,96.1
+2020-06-26 00:00:00,18.27,0.0,-0.0,0.0,3.17,96.05
+2020-06-26 01:00:00,18.0,0.0,-0.0,0.0,3.66,92.85
+2020-06-26 02:00:00,17.6,0.0,-0.0,0.0,3.52,92.85
+2020-06-26 03:00:00,17.05,1.0,0.0,1.0,3.45,89.7
+2020-06-26 04:00:00,16.48,36.0,0.0,36.0,3.24,89.65
+2020-06-26 05:00:00,16.52,84.0,0.0,84.0,2.69,86.6
+2020-06-26 06:00:00,17.02,151.0,4.3,149.0,3.03,83.7
+2020-06-26 07:00:00,18.23,532.0,563.55,192.0,3.31,75.45
+2020-06-26 08:00:00,19.18,687.0,702.58,180.0,3.24,65.75
+2020-06-26 09:00:00,20.2,684.0,441.03,326.0,3.24,59.35
+2020-06-26 10:00:00,21.01,671.0,312.39,400.0,3.24,53.6
+2020-06-26 11:00:00,21.67,715.0,367.17,390.0,3.24,50.05
+2020-06-26 12:00:00,22.22,799.0,608.02,274.0,2.97,48.45
+2020-06-26 13:00:00,22.56,779.0,730.18,192.0,2.69,45.25
+2020-06-26 14:00:00,22.82,562.0,364.5,303.0,2.41,45.25
+2020-06-26 15:00:00,22.87,540.0,647.7,158.0,2.07,45.25
+2020-06-26 16:00:00,22.77,346.0,377.96,176.0,1.79,45.25
+2020-06-26 17:00:00,22.37,168.0,129.94,129.0,1.66,46.75
+2020-06-26 18:00:00,21.37,26.0,0.0,26.0,1.31,57.55
+2020-06-26 19:00:00,19.79,0.0,0.0,0.0,1.52,63.6
+2020-06-26 20:00:00,20.26,0.0,-0.0,0.0,0.76,53.35
+2020-06-26 21:00:00,18.82,0.0,-0.0,0.0,1.1,61.2
+2020-06-26 22:00:00,16.97,0.0,-0.0,0.0,1.45,65.45
+2020-06-26 23:00:00,15.44,0.0,-0.0,0.0,1.66,72.55
+2020-06-27 00:00:00,15.02,0.0,-0.0,0.0,1.52,77.8
+2020-06-27 01:00:00,14.77,0.0,-0.0,0.0,1.45,77.75
+2020-06-27 02:00:00,14.09,0.0,-0.0,0.0,1.52,80.45
+2020-06-27 03:00:00,13.61,2.0,0.0,2.0,1.52,83.35
+2020-06-27 04:00:00,13.74,119.0,405.97,52.0,1.38,89.45
+2020-06-27 05:00:00,15.65,186.0,158.87,136.0,1.03,86.5
+2020-06-27 06:00:00,19.48,350.0,347.04,189.0,1.17,65.85
+2020-06-27 07:00:00,20.3,223.0,8.3,218.0,2.48,65.95
+2020-06-27 08:00:00,20.88,143.0,0.0,143.0,3.66,59.5
+2020-06-27 09:00:00,20.45,229.0,0.0,229.0,4.21,59.35
+2020-06-27 10:00:00,19.54,126.0,0.0,126.0,5.24,61.4
+2020-06-27 11:00:00,19.2,760.0,457.72,355.0,4.62,61.3
+2020-06-27 12:00:00,19.81,337.0,8.11,330.0,4.48,53.25
+2020-06-27 13:00:00,21.16,540.0,181.64,394.0,6.48,46.5
+2020-06-27 14:00:00,20.9,518.0,263.18,331.0,6.69,48.05
+2020-06-27 15:00:00,20.77,514.0,540.88,195.0,6.28,49.8
+2020-06-27 16:00:00,20.48,306.0,235.66,200.0,5.66,51.5
+2020-06-27 17:00:00,20.03,214.0,326.55,116.0,4.34,51.5
+2020-06-27 18:00:00,19.47,98.0,304.81,52.0,3.79,53.15
+2020-06-27 19:00:00,18.1,0.0,0.0,0.0,3.59,56.85
+2020-06-27 20:00:00,17.11,0.0,-0.0,0.0,2.9,56.75
+2020-06-27 21:00:00,16.26,0.0,-0.0,0.0,2.28,60.75
+2020-06-27 22:00:00,15.23,0.0,-0.0,0.0,2.0,67.45
+2020-06-27 23:00:00,13.95,0.0,-0.0,0.0,1.86,72.3
+2020-06-28 00:00:00,13.09,0.0,-0.0,0.0,1.86,77.5
+2020-06-28 01:00:00,12.77,0.0,-0.0,0.0,1.86,80.3
+2020-06-28 02:00:00,12.76,0.0,-0.0,0.0,2.0,80.3
+2020-06-28 03:00:00,13.21,0.0,0.0,0.0,2.28,77.5
+2020-06-28 04:00:00,13.86,79.0,97.63,63.0,2.34,80.4
+2020-06-28 05:00:00,15.18,83.0,0.0,83.0,2.34,77.8
+2020-06-28 06:00:00,16.85,236.0,69.13,204.0,2.83,72.7
+2020-06-28 07:00:00,17.48,224.0,8.31,219.0,2.97,75.4
+2020-06-28 08:00:00,18.23,361.0,50.0,325.0,3.59,72.9
+2020-06-28 09:00:00,19.07,266.0,1.23,265.0,4.07,68.1
+2020-06-28 10:00:00,20.58,212.0,0.0,212.0,5.93,55.45
+2020-06-28 11:00:00,20.71,324.0,4.52,320.0,6.0,57.45
+2020-06-28 12:00:00,20.45,577.0,177.29,424.0,5.86,61.5
+2020-06-28 13:00:00,20.53,444.0,77.15,382.0,4.9,59.5
+2020-06-28 14:00:00,20.73,476.0,192.84,339.0,4.41,61.6
+2020-06-28 15:00:00,20.62,470.0,403.59,232.0,4.41,66.05
+2020-06-28 16:00:00,20.73,351.0,406.92,168.0,4.21,68.4
+2020-06-28 17:00:00,20.13,204.0,283.35,119.0,2.97,70.7
+2020-06-28 18:00:00,19.72,101.0,338.37,50.0,2.69,73.15
+2020-06-28 19:00:00,19.44,0.0,0.0,0.0,2.55,70.55
+2020-06-28 20:00:00,18.63,0.0,-0.0,0.0,2.41,72.95
+2020-06-28 21:00:00,17.89,0.0,-0.0,0.0,2.28,75.4
+2020-06-28 22:00:00,17.11,0.0,-0.0,0.0,2.28,75.4
+2020-06-28 23:00:00,16.5,0.0,-0.0,0.0,2.21,78.0
+2020-06-29 00:00:00,15.87,0.0,-0.0,0.0,2.28,83.55
+2020-06-29 01:00:00,15.55,0.0,-0.0,0.0,2.34,83.55
+2020-06-29 02:00:00,15.42,0.0,-0.0,0.0,2.28,89.55
+2020-06-29 03:00:00,15.15,0.0,0.0,0.0,2.21,89.55
+2020-06-29 04:00:00,14.9,67.0,49.19,59.0,2.14,92.7
+2020-06-29 05:00:00,16.33,244.0,451.33,103.0,1.93,89.65
+2020-06-29 06:00:00,17.84,432.0,714.66,102.0,2.48,83.7
+2020-06-29 07:00:00,20.15,566.0,714.41,137.0,2.83,70.7
+2020-06-29 08:00:00,20.94,591.0,419.93,289.0,3.24,63.8
+2020-06-29 09:00:00,21.96,672.0,419.91,332.0,3.38,53.75
+2020-06-29 10:00:00,22.9,727.0,429.61,355.0,3.93,48.55
+2020-06-29 11:00:00,23.43,647.0,252.27,424.0,3.86,47.0
+2020-06-29 12:00:00,23.44,610.0,221.41,419.0,3.38,50.45
+2020-06-29 13:00:00,23.99,545.0,191.69,391.0,3.31,50.55
+2020-06-29 14:00:00,24.65,564.0,371.7,300.0,3.45,45.75
+2020-06-29 15:00:00,24.68,541.0,658.12,153.0,3.1,44.15
+2020-06-29 16:00:00,24.76,399.0,627.29,117.0,2.97,42.65
+2020-06-29 17:00:00,24.24,247.0,537.07,86.0,2.14,47.25
+2020-06-29 18:00:00,22.91,100.0,325.73,51.0,1.45,59.95
+2020-06-29 19:00:00,21.21,0.0,0.0,0.0,1.24,66.15
+2020-06-29 20:00:00,22.23,0.0,-0.0,0.0,0.69,50.2
+2020-06-29 21:00:00,21.28,0.0,-0.0,0.0,1.03,53.6
+2020-06-29 22:00:00,17.94,0.0,-0.0,0.0,1.52,70.3
+2020-06-29 23:00:00,15.9,0.0,-0.0,0.0,1.79,77.85
+2020-06-30 00:00:00,14.71,0.0,-0.0,0.0,1.79,83.45
+2020-06-30 01:00:00,13.72,0.0,-0.0,0.0,1.79,86.35
+2020-06-30 02:00:00,13.12,0.0,-0.0,0.0,1.79,89.4
+2020-06-30 03:00:00,13.01,0.0,0.0,0.0,1.72,89.4
+2020-06-30 04:00:00,13.96,13.0,0.0,13.0,1.45,89.5
+2020-06-30 05:00:00,16.47,73.0,0.0,73.0,1.45,80.8
+2020-06-30 06:00:00,18.6,254.0,99.87,208.0,2.55,70.45
+2020-06-30 07:00:00,18.9,523.0,548.85,194.0,3.03,78.25
+2020-06-30 08:00:00,19.79,638.0,555.52,239.0,3.38,73.15
+2020-06-30 09:00:00,20.43,557.0,203.98,392.0,3.93,68.3
+2020-06-30 10:00:00,21.22,274.0,1.16,273.0,4.0,63.9
+2020-06-30 11:00:00,21.86,516.0,95.08,432.0,4.34,59.7
+2020-06-30 12:00:00,22.45,650.0,286.46,403.0,4.48,55.8
+2020-06-30 13:00:00,22.85,669.0,427.11,326.0,4.55,50.3
+2020-06-30 14:00:00,22.84,568.0,380.29,298.0,4.48,48.55
+2020-06-30 15:00:00,22.7,541.0,656.68,154.0,4.28,46.85
+2020-06-30 16:00:00,20.06,407.0,663.24,109.0,2.85,45.78
+2020-06-30 17:00:00,19.81,171.0,143.58,128.0,2.67,49.67
+2020-06-30 18:00:00,19.57,78.0,133.3,58.0,2.49,53.56
+2020-06-30 19:00:00,19.32,0.0,0.0,0.0,2.32,57.45
+2020-06-30 20:00:00,19.07,0.0,-0.0,0.0,2.14,61.34
+2020-06-30 21:00:00,18.83,0.0,-0.0,0.0,1.96,65.23
+2020-06-30 22:00:00,18.58,0.0,-0.0,0.0,1.78,69.12
+2020-06-30 23:00:00,18.34,0.0,-0.0,0.0,1.61,73.01
+2020-07-01 00:00:00,18.09,0.0,-0.0,0.0,1.43,76.89
+2020-07-01 01:00:00,17.84,0.0,-0.0,0.0,1.25,80.78
+2020-07-01 02:00:00,17.6,0.0,-0.0,0.0,1.07,84.67
+2020-07-01 03:00:00,17.35,0.0,0.0,0.0,0.9,88.56
+2020-07-01 04:00:00,17.11,9.0,0.0,9.0,0.72,92.45
+2020-07-01 05:00:00,16.86,113.0,16.07,108.0,0.54,96.34
+2020-07-01 06:00:00,16.62,283.0,171.52,204.0,0.36,100.0
+2020-07-01 07:00:00,16.37,402.0,216.87,272.0,0.19,100.0
+2020-07-01 08:00:00,22.86,627.0,549.95,232.0,1.31,78.75
+2020-07-01 09:00:00,23.87,779.0,751.63,171.0,1.79,73.75
+2020-07-01 10:00:00,24.5,672.0,338.63,379.0,2.28,73.85
+2020-07-01 11:00:00,24.76,648.0,269.4,410.0,2.62,73.95
+2020-07-01 12:00:00,24.79,555.0,158.89,418.0,2.69,73.95
+2020-07-01 13:00:00,24.86,502.0,144.44,386.0,2.21,73.95
+2020-07-01 14:00:00,23.02,76.0,0.0,76.0,1.59,78.75
+2020-07-01 15:00:00,22.0,48.0,0.0,48.0,0.14,84.1
+2020-07-01 16:00:00,22.14,84.0,0.0,84.0,0.97,81.4
+2020-07-01 17:00:00,22.04,72.0,0.0,72.0,0.76,87.0
+2020-07-01 18:00:00,21.74,33.0,0.0,33.0,1.1,89.95
+2020-07-01 19:00:00,21.25,0.0,0.0,0.0,1.45,89.95
+2020-07-01 20:00:00,20.15,0.0,-0.0,0.0,1.03,92.95
+2020-07-01 21:00:00,19.18,0.0,-0.0,0.0,0.97,96.1
+2020-07-01 22:00:00,18.22,0.0,-0.0,0.0,1.24,96.1
+2020-07-01 23:00:00,18.27,0.0,-0.0,0.0,1.03,96.1
+2020-07-02 00:00:00,17.74,0.0,-0.0,0.0,1.03,96.05
+2020-07-02 01:00:00,16.72,0.0,-0.0,0.0,1.17,99.4
+2020-07-02 02:00:00,16.94,0.0,-0.0,0.0,0.97,99.4
+2020-07-02 03:00:00,17.05,0.0,0.0,0.0,0.9,99.4
+2020-07-02 04:00:00,17.24,9.0,0.0,9.0,0.69,99.4
+2020-07-02 05:00:00,18.22,24.0,0.0,24.0,0.28,96.1
+2020-07-02 06:00:00,19.02,79.0,0.0,79.0,0.41,96.1
+2020-07-02 07:00:00,21.01,172.0,0.0,172.0,0.41,86.9
+2020-07-02 08:00:00,22.11,181.0,0.0,181.0,0.9,81.4
+2020-07-02 09:00:00,23.28,260.0,1.24,259.0,1.45,76.2
+2020-07-02 10:00:00,23.96,451.0,60.15,399.0,1.79,76.3
+2020-07-02 11:00:00,24.73,868.0,789.46,171.0,2.34,69.15
+2020-07-02 12:00:00,22.74,708.0,418.9,347.0,2.28,78.75
+2020-07-02 13:00:00,22.51,409.0,54.81,365.0,1.45,81.4
+2020-07-02 14:00:00,22.62,219.0,1.41,218.0,1.17,78.75
+2020-07-02 15:00:00,21.74,48.0,0.0,48.0,2.28,84.1
+2020-07-02 16:00:00,21.39,39.0,0.0,39.0,1.59,86.95
+2020-07-02 17:00:00,21.45,21.0,0.0,21.0,1.66,86.95
+2020-07-02 18:00:00,21.05,26.0,0.0,26.0,1.24,86.95
+2020-07-02 19:00:00,20.63,0.0,0.0,0.0,1.24,89.9
+2020-07-02 20:00:00,19.6,0.0,-0.0,0.0,1.45,92.9
+2020-07-02 21:00:00,18.95,0.0,-0.0,0.0,1.31,99.4
+2020-07-02 22:00:00,18.11,0.0,-0.0,0.0,1.24,96.1
+2020-07-02 23:00:00,17.57,0.0,-0.0,0.0,1.1,99.4
+2020-07-03 00:00:00,17.93,0.0,-0.0,0.0,0.69,99.4
+2020-07-03 01:00:00,17.91,0.0,-0.0,0.0,0.76,99.4
+2020-07-03 02:00:00,17.61,0.0,-0.0,0.0,0.76,99.4
+2020-07-03 03:00:00,17.56,0.0,0.0,0.0,0.55,99.4
+2020-07-03 04:00:00,17.72,17.0,0.0,17.0,0.62,99.4
+2020-07-03 05:00:00,17.8,80.0,0.0,80.0,0.48,99.4
+2020-07-03 06:00:00,17.91,194.0,28.38,181.0,0.62,99.4
+2020-07-03 07:00:00,19.33,362.0,139.0,279.0,0.69,92.9
+2020-07-03 08:00:00,21.28,683.0,730.24,160.0,1.03,84.05
+2020-07-03 09:00:00,22.85,809.0,821.39,146.0,1.31,76.15
+2020-07-03 10:00:00,24.09,843.0,755.95,190.0,1.59,66.75
+2020-07-03 11:00:00,24.6,677.0,312.83,401.0,1.93,64.6
+2020-07-03 12:00:00,25.33,654.0,303.04,393.0,1.93,62.55
+2020-07-03 13:00:00,25.53,798.0,808.95,149.0,2.07,62.55
+2020-07-03 14:00:00,25.66,667.0,699.3,171.0,2.28,60.6
+2020-07-03 15:00:00,25.54,548.0,701.62,135.0,2.14,62.55
+2020-07-03 16:00:00,24.84,392.0,608.62,119.0,1.66,64.6
+2020-07-03 17:00:00,24.5,233.0,472.22,92.0,1.24,66.75
+2020-07-03 18:00:00,23.64,91.0,255.11,53.0,0.76,76.3
+2020-07-03 19:00:00,23.84,0.0,0.0,0.0,0.62,68.95
+2020-07-03 20:00:00,22.51,0.0,-0.0,0.0,0.9,76.1
+2020-07-03 21:00:00,20.68,0.0,-0.0,0.0,1.24,81.2
+2020-07-03 22:00:00,18.83,0.0,-0.0,0.0,1.66,89.75
+2020-07-03 23:00:00,17.61,0.0,-0.0,0.0,1.72,89.75
+2020-07-04 00:00:00,16.66,0.0,-0.0,0.0,1.72,92.8
+2020-07-04 01:00:00,16.37,0.0,-0.0,0.0,1.59,96.05
+2020-07-04 02:00:00,15.62,0.0,-0.0,0.0,1.59,96.0
+2020-07-04 03:00:00,15.32,0.0,0.0,0.0,1.59,99.4
+2020-07-04 04:00:00,15.64,64.0,51.01,56.0,1.38,96.0
+2020-07-04 05:00:00,18.06,224.0,371.47,110.0,0.9,92.85
+2020-07-04 06:00:00,21.61,374.0,492.74,149.0,0.9,81.35
+2020-07-04 07:00:00,22.27,534.0,622.63,163.0,1.93,78.7
+2020-07-04 08:00:00,23.17,668.0,685.22,178.0,2.28,73.7
+2020-07-04 09:00:00,23.86,738.0,620.18,238.0,2.55,73.75
+2020-07-04 10:00:00,24.42,751.0,507.53,313.0,3.03,71.4
+2020-07-04 11:00:00,23.29,502.0,88.48,424.0,2.9,78.85
+2020-07-04 12:00:00,23.78,616.0,241.66,408.0,2.14,78.9
+2020-07-04 13:00:00,23.39,562.0,228.24,379.0,2.76,78.85
+2020-07-04 14:00:00,22.14,61.0,0.0,61.0,2.69,81.4
+2020-07-04 15:00:00,22.73,49.0,0.0,49.0,1.86,78.75
+2020-07-04 16:00:00,23.28,35.0,0.0,35.0,1.86,76.2
+2020-07-04 17:00:00,22.27,33.0,0.0,33.0,2.14,78.7
+2020-07-04 18:00:00,21.31,87.0,222.58,54.0,1.52,84.05
+2020-07-04 19:00:00,20.26,0.0,0.0,0.0,1.93,86.85
+2020-07-04 20:00:00,19.34,0.0,-0.0,0.0,2.0,92.9
+2020-07-04 21:00:00,18.94,0.0,-0.0,0.0,2.0,96.1
+2020-07-04 22:00:00,18.42,0.0,-0.0,0.0,2.07,92.85
+2020-07-04 23:00:00,18.33,0.0,-0.0,0.0,2.0,92.85
+2020-07-05 00:00:00,17.45,0.0,-0.0,0.0,2.0,92.85
+2020-07-05 01:00:00,17.27,0.0,-0.0,0.0,1.79,92.85
+2020-07-05 02:00:00,17.0,0.0,-0.0,0.0,1.93,92.85
+2020-07-05 03:00:00,16.5,0.0,0.0,0.0,1.93,92.8
+2020-07-05 04:00:00,16.78,27.0,0.0,27.0,1.86,96.05
+2020-07-05 05:00:00,17.61,84.0,0.0,84.0,1.93,92.85
+2020-07-05 06:00:00,18.16,132.0,0.0,132.0,2.62,89.75
+2020-07-05 07:00:00,19.3,248.0,20.18,236.0,1.79,92.9
+2020-07-05 08:00:00,20.14,602.0,467.83,268.0,2.21,86.85
+2020-07-05 09:00:00,21.16,802.0,806.0,153.0,2.76,75.95
+2020-07-05 10:00:00,21.61,600.0,211.1,418.0,3.03,66.25
+2020-07-05 11:00:00,22.05,744.0,443.89,353.0,2.97,61.95
+2020-07-05 12:00:00,22.69,876.0,847.61,147.0,2.9,57.9
+2020-07-05 13:00:00,23.13,793.0,792.56,158.0,3.24,54.1
+2020-07-05 14:00:00,23.3,678.0,732.76,159.0,3.45,52.25
+2020-07-05 15:00:00,23.35,530.0,627.96,161.0,3.38,52.25
+2020-07-05 16:00:00,22.86,398.0,632.47,115.0,3.31,54.0
+2020-07-05 17:00:00,22.31,243.0,528.05,86.0,2.55,55.8
+2020-07-05 18:00:00,21.31,95.0,298.37,51.0,1.86,61.7
+2020-07-05 19:00:00,19.95,0.0,0.0,0.0,1.59,70.65
+2020-07-05 20:00:00,18.96,0.0,-0.0,0.0,1.24,72.95
+2020-07-05 21:00:00,19.71,0.0,-0.0,0.0,0.9,61.4
+2020-07-05 22:00:00,19.74,0.0,-0.0,0.0,0.48,61.4
+2020-07-05 23:00:00,17.2,0.0,-0.0,0.0,1.38,70.3
+2020-07-06 00:00:00,15.25,0.0,-0.0,0.0,1.59,80.6
+2020-07-06 01:00:00,13.97,0.0,-0.0,0.0,1.79,86.35
+2020-07-06 02:00:00,13.34,0.0,-0.0,0.0,1.66,89.4
+2020-07-06 03:00:00,13.18,0.0,0.0,0.0,1.59,89.4
+2020-07-06 04:00:00,13.55,81.0,143.35,59.0,1.45,89.45
+2020-07-06 05:00:00,15.97,247.0,520.26,89.0,0.9,89.6
+2020-07-06 06:00:00,19.59,404.0,637.03,115.0,0.69,73.15
+2020-07-06 07:00:00,21.62,566.0,740.08,127.0,0.55,64.0
+2020-07-06 08:00:00,22.83,629.0,551.41,236.0,0.97,54.0
+2020-07-06 09:00:00,23.45,792.0,782.2,163.0,1.38,50.45
+2020-07-06 10:00:00,23.87,608.0,224.1,415.0,1.79,48.8
+2020-07-06 11:00:00,23.96,596.0,187.49,431.0,2.0,48.8
+2020-07-06 12:00:00,23.8,597.0,210.62,416.0,2.07,48.8
+2020-07-06 13:00:00,23.54,213.0,0.0,213.0,2.28,50.45
+2020-07-06 14:00:00,23.15,140.0,0.0,140.0,2.41,52.25
+2020-07-06 15:00:00,22.69,96.0,0.0,96.0,2.69,55.9
+2020-07-06 16:00:00,21.98,106.0,0.0,106.0,2.62,64.0
+2020-07-06 17:00:00,21.39,66.0,0.0,66.0,2.0,68.5
+2020-07-06 18:00:00,20.78,37.0,6.82,36.0,1.38,73.3
+2020-07-06 19:00:00,19.5,0.0,0.0,0.0,1.17,86.8
+2020-07-06 20:00:00,18.27,0.0,-0.0,0.0,1.24,89.75
+2020-07-06 21:00:00,17.37,0.0,-0.0,0.0,1.52,92.85
+2020-07-06 22:00:00,16.72,0.0,-0.0,0.0,1.66,92.8
+2020-07-06 23:00:00,16.38,0.0,-0.0,0.0,1.59,92.8
+2020-07-07 00:00:00,15.88,0.0,-0.0,0.0,1.66,96.0
+2020-07-07 01:00:00,15.28,0.0,-0.0,0.0,1.66,96.0
+2020-07-07 02:00:00,14.61,0.0,-0.0,0.0,1.79,92.7
+2020-07-07 03:00:00,14.16,0.0,0.0,0.0,1.86,92.7
+2020-07-07 04:00:00,14.23,79.0,138.46,58.0,1.79,92.7
+2020-07-07 05:00:00,16.46,250.0,543.07,86.0,1.66,89.65
+2020-07-07 06:00:00,18.48,398.0,621.55,117.0,2.28,81.0
+2020-07-07 07:00:00,19.16,296.0,57.46,262.0,2.48,78.3
+2020-07-07 08:00:00,20.15,522.0,281.12,322.0,2.28,73.2
+2020-07-07 09:00:00,21.02,680.0,465.74,306.0,2.14,70.8
+2020-07-07 10:00:00,21.64,167.0,0.0,167.0,1.93,68.6
+2020-07-07 11:00:00,22.35,871.0,790.49,176.0,1.59,66.35
+2020-07-07 12:00:00,22.82,723.0,446.07,340.0,1.45,64.2
+2020-07-07 13:00:00,23.21,225.0,0.0,225.0,1.59,62.15
+2020-07-07 14:00:00,23.49,176.0,0.0,176.0,2.07,58.0
+2020-07-07 15:00:00,21.83,377.0,179.09,272.0,3.03,61.85
+2020-07-07 16:00:00,19.79,70.0,0.0,70.0,2.69,73.15
+2020-07-07 17:00:00,19.39,37.0,0.0,37.0,1.86,73.05
+2020-07-07 18:00:00,19.17,18.0,0.0,18.0,1.59,73.05
+2020-07-07 19:00:00,18.09,0.0,0.0,0.0,2.07,72.95
+2020-07-07 20:00:00,17.64,0.0,-0.0,0.0,1.86,75.45
+2020-07-07 21:00:00,17.24,0.0,-0.0,0.0,2.14,75.4
+2020-07-07 22:00:00,16.77,0.0,-0.0,0.0,2.28,75.3
+2020-07-07 23:00:00,16.3,0.0,-0.0,0.0,2.41,75.25
+2020-07-08 00:00:00,15.84,0.0,-0.0,0.0,2.48,75.15
+2020-07-08 01:00:00,15.31,0.0,-0.0,0.0,2.76,77.8
+2020-07-08 02:00:00,15.06,0.0,-0.0,0.0,2.83,75.1
+2020-07-08 03:00:00,14.94,0.0,0.0,0.0,2.97,77.75
+2020-07-08 04:00:00,14.95,71.0,93.46,57.0,3.24,77.75
+2020-07-08 05:00:00,15.27,232.0,443.01,99.0,3.45,77.8
+2020-07-08 06:00:00,16.06,242.0,91.02,201.0,4.14,70.1
+2020-07-08 07:00:00,16.12,347.0,118.59,277.0,4.34,72.65
+2020-07-08 08:00:00,16.87,540.0,316.85,315.0,4.21,70.2
+2020-07-08 09:00:00,17.92,508.0,144.66,392.0,4.28,67.95
+2020-07-08 10:00:00,18.67,632.0,260.7,408.0,4.55,68.05
+2020-07-08 11:00:00,18.75,542.0,124.1,433.0,4.48,70.45
+2020-07-08 12:00:00,19.44,845.0,763.59,190.0,4.55,68.1
+2020-07-08 13:00:00,19.69,691.0,491.8,298.0,4.83,65.85
+2020-07-08 14:00:00,19.38,148.0,0.0,148.0,5.17,68.1
+2020-07-08 15:00:00,18.81,511.0,555.09,186.0,5.24,68.05
+2020-07-08 16:00:00,18.6,198.0,35.94,182.0,5.17,65.65
+2020-07-08 17:00:00,18.36,134.0,54.29,118.0,5.31,61.2
+2020-07-08 18:00:00,16.82,75.0,138.44,55.0,5.24,67.75
+2020-07-08 19:00:00,15.59,0.0,0.0,0.0,5.03,72.55
+2020-07-08 20:00:00,15.36,0.0,-0.0,0.0,4.62,69.9
+2020-07-08 21:00:00,15.03,0.0,-0.0,0.0,4.62,69.9
+2020-07-08 22:00:00,14.8,0.0,-0.0,0.0,4.76,69.85
+2020-07-08 23:00:00,14.57,0.0,-0.0,0.0,4.9,69.85
+2020-07-09 00:00:00,14.42,0.0,-0.0,0.0,4.9,72.3
+2020-07-09 01:00:00,14.32,0.0,-0.0,0.0,4.69,74.95
+2020-07-09 02:00:00,14.34,0.0,-0.0,0.0,4.55,74.95
+2020-07-09 03:00:00,14.26,0.0,0.0,0.0,4.34,74.95
+2020-07-09 04:00:00,14.07,10.0,0.0,10.0,4.41,74.95
+2020-07-09 05:00:00,13.88,105.0,13.41,101.0,3.86,80.4
+2020-07-09 06:00:00,14.31,127.0,0.0,127.0,4.69,77.65
+2020-07-09 07:00:00,14.93,111.0,0.0,111.0,4.34,80.55
+2020-07-09 08:00:00,15.42,432.0,125.57,343.0,4.14,77.8
+2020-07-09 09:00:00,16.11,0.0,0.0,0.0,4.07,72.65
+2020-07-09 10:00:00,16.95,0.0,0.0,0.0,4.07,70.2
+2020-07-09 11:00:00,17.8,811.0,597.27,287.0,4.21,65.55
+2020-07-09 12:00:00,18.38,653.0,294.08,401.0,4.34,63.4
+2020-07-09 13:00:00,18.52,580.0,249.29,381.0,4.41,61.2
+2020-07-09 14:00:00,18.52,479.0,199.89,338.0,4.62,56.95
+2020-07-09 15:00:00,18.01,478.0,431.05,226.0,4.14,53.0
+2020-07-09 16:00:00,18.08,197.0,33.77,182.0,3.79,51.15
+2020-07-09 17:00:00,17.63,0.0,0.0,0.0,3.31,51.0
+2020-07-09 18:00:00,16.97,0.0,0.0,0.0,2.62,54.6
+2020-07-09 19:00:00,16.13,0.0,0.0,0.0,2.48,56.5
+2020-07-09 20:00:00,15.08,0.0,-0.0,0.0,2.14,60.5
+2020-07-09 21:00:00,14.0,0.0,-0.0,0.0,2.0,64.85
+2020-07-09 22:00:00,12.95,0.0,-0.0,0.0,1.86,74.7
+2020-07-09 23:00:00,11.97,0.0,-0.0,0.0,1.86,77.35
+2020-07-10 00:00:00,11.0,0.0,-0.0,0.0,1.93,80.1
+2020-07-10 01:00:00,10.51,0.0,-0.0,0.0,2.07,83.0
+2020-07-10 02:00:00,10.43,0.0,-0.0,0.0,2.21,86.0
+2020-07-10 03:00:00,10.82,0.0,0.0,0.0,2.41,83.0
+2020-07-10 04:00:00,11.77,18.0,0.0,18.0,2.69,80.15
+2020-07-10 05:00:00,12.62,59.0,0.0,59.0,2.69,80.3
+2020-07-10 06:00:00,13.11,372.0,498.88,149.0,2.48,83.25
+2020-07-10 07:00:00,14.09,402.0,221.42,272.0,3.52,74.95
+2020-07-10 08:00:00,15.2,463.0,171.07,342.0,3.31,67.45
+2020-07-10 09:00:00,16.72,456.0,87.57,386.0,3.45,60.85
+2020-07-10 10:00:00,17.75,271.0,1.17,270.0,3.66,58.9
+2020-07-10 11:00:00,18.31,781.0,526.07,320.0,4.07,59.05
+2020-07-10 12:00:00,18.45,835.0,727.83,212.0,4.48,59.05
+2020-07-10 13:00:00,18.5,670.0,435.19,323.0,4.9,56.95
+2020-07-10 14:00:00,18.81,407.0,99.36,337.0,5.1,56.95
+2020-07-10 15:00:00,17.97,130.0,0.0,130.0,5.52,58.9
+2020-07-10 16:00:00,17.52,247.0,106.06,200.0,4.83,58.9
+2020-07-10 17:00:00,16.56,30.0,0.0,30.0,4.48,63.05
+2020-07-10 18:00:00,15.09,46.0,14.09,44.0,4.34,72.45
+2020-07-10 19:00:00,13.52,0.0,0.0,0.0,3.79,72.2
+2020-07-10 20:00:00,13.26,0.0,-0.0,0.0,3.66,77.5
+2020-07-10 21:00:00,12.99,0.0,-0.0,0.0,3.86,80.35
+2020-07-10 22:00:00,12.38,0.0,-0.0,0.0,4.07,89.35
+2020-07-10 23:00:00,12.31,0.0,-0.0,0.0,4.76,89.35
+2020-07-11 00:00:00,12.23,0.0,-0.0,0.0,4.69,92.6
+2020-07-11 01:00:00,12.13,0.0,-0.0,0.0,4.34,89.35
+2020-07-11 02:00:00,11.96,0.0,-0.0,0.0,4.14,89.35
+2020-07-11 03:00:00,11.76,0.0,0.0,0.0,4.0,89.3
+2020-07-11 04:00:00,11.89,43.0,6.96,42.0,3.72,89.3
+2020-07-11 05:00:00,12.1,82.0,0.0,82.0,3.52,86.2
+2020-07-11 06:00:00,12.49,138.0,2.25,137.0,3.93,83.25
+2020-07-11 07:00:00,12.96,202.0,5.12,199.0,3.59,83.25
+2020-07-11 08:00:00,13.4,413.0,106.26,338.0,3.79,77.5
+2020-07-11 09:00:00,13.85,503.0,139.09,392.0,3.72,72.2
+2020-07-11 10:00:00,14.57,303.0,3.51,300.0,3.86,64.95
+2020-07-11 11:00:00,16.07,349.0,9.14,341.0,4.48,58.6
+2020-07-11 12:00:00,16.84,372.0,18.71,356.0,4.0,58.7
+2020-07-11 13:00:00,17.37,235.0,0.0,235.0,3.72,60.95
+2020-07-11 14:00:00,17.81,586.0,442.08,275.0,3.45,58.9
+2020-07-11 15:00:00,18.02,499.0,516.63,198.0,3.1,56.95
+2020-07-11 16:00:00,18.17,112.0,0.0,112.0,2.97,54.95
+2020-07-11 17:00:00,17.75,129.0,48.07,115.0,2.62,56.85
+2020-07-11 18:00:00,16.98,42.0,14.23,40.0,2.34,63.05
+2020-07-11 19:00:00,15.26,0.0,0.0,0.0,2.14,72.45
+2020-07-11 20:00:00,14.39,0.0,-0.0,0.0,2.28,77.65
+2020-07-11 21:00:00,13.93,0.0,-0.0,0.0,2.48,83.35
+2020-07-11 22:00:00,13.41,0.0,-0.0,0.0,2.21,86.3
+2020-07-11 23:00:00,12.89,0.0,-0.0,0.0,1.93,89.4
+2020-07-12 00:00:00,12.48,0.0,-0.0,0.0,2.0,86.25
+2020-07-12 01:00:00,12.17,0.0,-0.0,0.0,1.93,89.35
+2020-07-12 02:00:00,11.71,0.0,-0.0,0.0,1.93,92.55
+2020-07-12 03:00:00,11.45,0.0,0.0,0.0,1.86,95.9
+2020-07-12 04:00:00,11.91,17.0,0.0,17.0,1.52,95.9
+2020-07-12 05:00:00,13.16,144.0,78.64,121.0,1.17,92.65
+2020-07-12 06:00:00,14.27,225.0,69.93,194.0,1.66,86.4
+2020-07-12 07:00:00,15.36,368.0,161.02,274.0,1.52,83.5
+2020-07-12 08:00:00,16.54,450.0,157.61,339.0,2.07,72.7
+2020-07-12 09:00:00,17.67,623.0,338.92,353.0,2.0,67.95
+2020-07-12 10:00:00,18.85,494.0,92.44,415.0,2.21,63.4
+2020-07-12 11:00:00,19.74,503.0,89.24,425.0,2.55,59.25
+2020-07-12 12:00:00,20.25,401.0,30.45,375.0,2.83,57.3
+2020-07-12 13:00:00,20.66,256.0,1.26,255.0,2.55,55.45
+2020-07-12 14:00:00,20.99,533.0,314.62,312.0,2.41,55.45
+2020-07-12 15:00:00,21.31,394.0,216.68,268.0,2.21,53.6
+2020-07-12 16:00:00,21.09,320.0,310.82,183.0,2.0,55.55
+2020-07-12 17:00:00,20.53,139.0,69.0,119.0,1.31,63.7
+2020-07-12 18:00:00,19.72,42.0,14.38,40.0,1.38,70.65
+2020-07-12 19:00:00,18.83,0.0,-0.0,0.0,1.72,70.45
+2020-07-12 20:00:00,17.77,0.0,-0.0,0.0,1.79,72.9
+2020-07-12 21:00:00,16.95,0.0,-0.0,0.0,1.86,78.0
+2020-07-12 22:00:00,16.27,0.0,-0.0,0.0,2.07,77.95
+2020-07-12 23:00:00,16.01,0.0,-0.0,0.0,2.07,77.95
+2020-07-13 00:00:00,16.13,0.0,-0.0,0.0,2.14,77.95
+2020-07-13 01:00:00,15.83,0.0,-0.0,0.0,2.14,80.65
+2020-07-13 02:00:00,15.81,0.0,-0.0,0.0,2.14,83.55
+2020-07-13 03:00:00,15.8,0.0,-0.0,0.0,2.07,83.55
+2020-07-13 04:00:00,15.81,17.0,0.0,17.0,2.34,86.5
+2020-07-13 05:00:00,16.69,222.0,427.02,98.0,2.69,86.6
+2020-07-13 06:00:00,17.32,379.0,566.41,129.0,3.45,86.65
+2020-07-13 07:00:00,18.86,542.0,692.44,139.0,3.52,81.0
+2020-07-13 08:00:00,19.78,640.0,611.93,210.0,2.9,73.15
+2020-07-13 09:00:00,21.0,733.0,616.19,243.0,2.34,63.8
+2020-07-13 10:00:00,22.05,774.0,571.92,286.0,2.07,55.65
+2020-07-13 11:00:00,23.01,809.0,612.91,274.0,2.0,48.55
+2020-07-13 12:00:00,23.72,840.0,763.41,189.0,1.93,45.5
+2020-07-13 13:00:00,24.3,372.0,31.48,347.0,1.86,44.05
+2020-07-13 14:00:00,24.44,681.0,758.6,149.0,1.24,45.6
+2020-07-13 15:00:00,24.39,526.0,630.72,160.0,0.41,45.6
+2020-07-13 16:00:00,24.43,358.0,468.76,152.0,0.48,47.25
+2020-07-13 17:00:00,23.37,215.0,388.34,103.0,0.41,71.25
+2020-07-13 18:00:00,23.0,89.0,298.36,48.0,0.48,64.2
+2020-07-13 19:00:00,21.23,0.0,-0.0,0.0,1.93,63.9
+2020-07-13 20:00:00,19.97,0.0,-0.0,0.0,1.93,70.65
+2020-07-13 21:00:00,18.53,0.0,-0.0,0.0,2.0,75.55
+2020-07-13 22:00:00,17.56,0.0,-0.0,0.0,1.93,78.15
+2020-07-13 23:00:00,16.82,0.0,-0.0,0.0,1.93,83.65
+2020-07-14 00:00:00,16.42,0.0,-0.0,0.0,1.93,89.65
+2020-07-14 01:00:00,16.56,0.0,-0.0,0.0,2.0,86.6
+2020-07-14 02:00:00,16.41,0.0,-0.0,0.0,2.07,89.65
+2020-07-14 03:00:00,16.5,0.0,-0.0,0.0,2.0,89.65
+2020-07-14 04:00:00,16.62,9.0,0.0,9.0,1.93,89.65
+2020-07-14 05:00:00,17.88,30.0,0.0,30.0,1.79,86.7
+2020-07-14 06:00:00,20.02,60.0,0.0,60.0,1.59,83.9
+2020-07-14 07:00:00,20.05,114.0,0.0,114.0,1.79,86.85
+2020-07-14 08:00:00,21.04,443.0,161.19,330.0,1.66,84.05
+2020-07-14 09:00:00,22.55,613.0,342.69,341.0,2.28,76.1
+2020-07-14 10:00:00,23.48,538.0,147.9,412.0,2.62,71.25
+2020-07-14 11:00:00,23.97,139.0,0.0,139.0,2.83,71.35
+2020-07-14 12:00:00,23.98,294.0,3.52,291.0,2.62,71.35
+2020-07-14 13:00:00,23.67,624.0,368.21,332.0,2.34,73.75
+2020-07-14 14:00:00,24.02,593.0,499.95,243.0,2.41,73.75
+2020-07-14 15:00:00,22.7,390.0,224.53,260.0,2.28,78.75
+2020-07-14 16:00:00,22.39,341.0,424.61,155.0,1.79,81.4
+2020-07-14 17:00:00,22.47,222.0,467.14,88.0,0.76,81.4
+2020-07-14 18:00:00,22.28,85.0,272.66,48.0,0.83,84.15
+2020-07-14 19:00:00,23.37,0.0,-0.0,0.0,0.62,73.7
+2020-07-14 20:00:00,20.21,0.0,-0.0,0.0,1.79,86.85
+2020-07-14 21:00:00,18.64,0.0,-0.0,0.0,1.79,92.85
+2020-07-14 22:00:00,17.51,0.0,-0.0,0.0,1.79,92.85
+2020-07-14 23:00:00,16.75,0.0,-0.0,0.0,1.72,96.05
+2020-07-15 00:00:00,16.28,0.0,-0.0,0.0,1.72,96.05
+2020-07-15 01:00:00,16.17,0.0,-0.0,0.0,1.86,96.05
+2020-07-15 02:00:00,16.16,0.0,-0.0,0.0,1.93,92.8
+2020-07-15 03:00:00,16.25,0.0,-0.0,0.0,2.0,92.8
+2020-07-15 04:00:00,16.73,7.0,0.0,7.0,1.79,92.8
+2020-07-15 05:00:00,18.27,20.0,0.0,20.0,1.31,92.85
+2020-07-15 06:00:00,20.81,56.0,0.0,56.0,1.1,84.05
+2020-07-15 07:00:00,20.58,70.0,0.0,70.0,2.0,84.05
+2020-07-15 08:00:00,21.3,92.0,0.0,92.0,1.45,81.3
+2020-07-15 09:00:00,21.93,279.0,3.79,276.0,1.52,78.65
+2020-07-15 10:00:00,22.94,715.0,457.38,326.0,1.45,73.6
+2020-07-15 11:00:00,23.77,826.0,702.04,215.0,2.0,68.95
+2020-07-15 12:00:00,23.67,650.0,319.89,378.0,1.72,68.95
+2020-07-15 13:00:00,23.16,411.0,60.62,363.0,1.86,71.25
+2020-07-15 14:00:00,22.57,334.0,41.5,305.0,0.97,78.75
+2020-07-15 15:00:00,23.14,72.0,0.0,72.0,1.66,76.2
+2020-07-15 16:00:00,23.53,200.0,45.81,180.0,1.79,73.7
+2020-07-15 17:00:00,23.63,216.0,434.79,92.0,1.52,71.35
+2020-07-15 18:00:00,23.2,79.0,231.56,48.0,1.38,76.2
+2020-07-15 19:00:00,21.58,0.0,-0.0,0.0,1.79,78.65
+2020-07-15 20:00:00,20.03,0.0,-0.0,0.0,2.0,86.85
+2020-07-15 21:00:00,18.98,0.0,-0.0,0.0,2.14,92.85
+2020-07-15 22:00:00,18.34,0.0,-0.0,0.0,2.21,89.75
+2020-07-15 23:00:00,17.72,0.0,-0.0,0.0,2.14,89.75
+2020-07-16 00:00:00,17.21,0.0,-0.0,0.0,2.21,89.7
+2020-07-16 01:00:00,16.76,0.0,-0.0,0.0,2.34,89.65
+2020-07-16 02:00:00,16.31,0.0,-0.0,0.0,2.28,89.65
+2020-07-16 03:00:00,15.79,0.0,-0.0,0.0,2.21,89.6
+2020-07-16 04:00:00,15.52,52.0,45.37,46.0,2.0,89.6
+2020-07-16 05:00:00,17.15,215.0,419.39,96.0,1.52,92.85
+2020-07-16 06:00:00,20.27,367.0,537.64,133.0,1.38,83.95
+2020-07-16 07:00:00,21.66,532.0,676.61,142.0,2.0,78.65
+2020-07-16 08:00:00,22.89,679.0,765.47,145.0,1.86,71.15
+2020-07-16 09:00:00,23.99,706.0,555.27,267.0,1.86,64.4
+2020-07-16 10:00:00,24.53,815.0,701.97,219.0,1.93,58.2
+2020-07-16 11:00:00,24.77,789.0,574.26,290.0,1.86,54.45
+2020-07-16 12:00:00,25.03,834.0,759.75,189.0,1.86,54.45
+2020-07-16 13:00:00,25.38,771.0,754.0,175.0,1.93,50.95
+2020-07-16 14:00:00,25.33,630.0,596.51,214.0,1.86,50.95
+2020-07-16 15:00:00,25.1,535.0,689.07,138.0,1.66,50.95
+2020-07-16 16:00:00,25.01,374.0,572.48,125.0,1.45,52.6
+2020-07-16 17:00:00,24.34,190.0,268.13,114.0,1.17,62.35
+2020-07-16 18:00:00,23.4,80.0,242.52,48.0,1.31,68.85
+2020-07-16 19:00:00,21.72,0.0,-0.0,0.0,1.72,66.25
+2020-07-16 20:00:00,19.89,0.0,-0.0,0.0,1.93,73.15
+2020-07-16 21:00:00,18.58,0.0,-0.0,0.0,2.14,72.95
+2020-07-16 22:00:00,17.86,0.0,-0.0,0.0,2.28,75.45
+2020-07-16 23:00:00,17.98,0.0,-0.0,0.0,2.28,72.9
+2020-07-17 00:00:00,17.73,0.0,-0.0,0.0,2.34,72.9
+2020-07-17 01:00:00,17.23,0.0,-0.0,0.0,2.34,72.8
+2020-07-17 02:00:00,17.23,0.0,-0.0,0.0,2.41,72.8
+2020-07-17 03:00:00,16.96,0.0,-0.0,0.0,2.41,78.0
+2020-07-17 04:00:00,17.3,46.0,30.83,42.0,2.55,78.1
+2020-07-17 05:00:00,18.82,140.0,88.84,115.0,2.55,78.25
+2020-07-17 06:00:00,20.96,371.0,586.49,117.0,2.62,75.85
+2020-07-17 07:00:00,23.26,533.0,703.31,129.0,2.76,68.85
+2020-07-17 08:00:00,24.79,671.0,764.57,139.0,3.31,64.6
+2020-07-17 09:00:00,26.0,780.0,803.59,146.0,3.79,60.6
+2020-07-17 10:00:00,27.15,867.0,871.95,128.0,4.21,55.05
+2020-07-17 11:00:00,27.93,831.0,719.3,207.0,4.28,53.35
+2020-07-17 12:00:00,28.82,194.0,0.0,194.0,4.21,50.05
+2020-07-17 13:00:00,28.22,91.0,0.0,91.0,3.59,51.65
+2020-07-17 14:00:00,26.57,60.0,0.0,60.0,2.21,60.7
+2020-07-17 15:00:00,26.18,47.0,0.0,47.0,0.97,62.8
+2020-07-17 16:00:00,26.31,33.0,0.0,33.0,0.28,62.8
+2020-07-17 17:00:00,26.1,142.0,92.33,116.0,0.48,64.95
+2020-07-17 18:00:00,23.08,73.0,200.13,47.0,1.72,78.85
+2020-07-17 19:00:00,20.49,0.0,-0.0,0.0,1.38,92.95
+2020-07-17 20:00:00,19.72,0.0,-0.0,0.0,0.76,96.1
+2020-07-17 21:00:00,19.19,0.0,-0.0,0.0,0.83,96.1
+2020-07-17 22:00:00,18.56,0.0,-0.0,0.0,1.24,96.1
+2020-07-17 23:00:00,18.6,0.0,-0.0,0.0,1.24,96.1
+2020-07-18 00:00:00,18.73,0.0,-0.0,0.0,1.24,99.4
+2020-07-18 01:00:00,18.33,0.0,-0.0,0.0,0.76,96.1
+2020-07-18 02:00:00,17.95,0.0,-0.0,0.0,0.9,99.4
+2020-07-18 03:00:00,17.92,0.0,-0.0,0.0,1.24,99.4
+2020-07-18 04:00:00,17.58,7.0,0.0,7.0,4.14,92.85
+2020-07-18 05:00:00,15.73,19.0,0.0,19.0,6.14,89.6
+2020-07-18 06:00:00,15.64,51.0,0.0,51.0,5.17,83.55
+2020-07-18 07:00:00,15.93,274.0,47.17,247.0,4.14,77.85
+2020-07-18 08:00:00,16.69,110.0,0.0,110.0,3.79,72.7
+2020-07-18 09:00:00,16.83,112.0,0.0,112.0,4.14,72.7
+2020-07-18 10:00:00,16.88,142.0,0.0,142.0,4.07,75.3
+2020-07-18 11:00:00,16.4,141.0,0.0,141.0,3.31,80.75
+2020-07-18 12:00:00,15.89,133.0,0.0,133.0,2.9,86.5
+2020-07-18 13:00:00,15.62,147.0,0.0,147.0,3.38,86.5
+2020-07-18 14:00:00,14.85,125.0,0.0,125.0,2.9,89.5
+2020-07-18 15:00:00,14.94,184.0,1.75,183.0,2.62,92.7
+2020-07-18 16:00:00,15.03,104.0,0.0,104.0,2.48,89.55
+2020-07-18 17:00:00,15.26,39.0,0.0,39.0,2.21,89.55
+2020-07-18 18:00:00,15.48,24.0,0.0,24.0,2.28,86.5
+2020-07-18 19:00:00,14.79,0.0,-0.0,0.0,2.62,83.45
+2020-07-18 20:00:00,14.61,0.0,-0.0,0.0,3.03,83.45
+2020-07-18 21:00:00,14.5,0.0,-0.0,0.0,3.24,83.45
+2020-07-18 22:00:00,14.55,0.0,-0.0,0.0,3.52,80.55
+2020-07-18 23:00:00,14.42,0.0,-0.0,0.0,3.79,83.4
+2020-07-19 00:00:00,14.2,0.0,-0.0,0.0,3.93,80.45
+2020-07-19 01:00:00,14.27,0.0,-0.0,0.0,4.0,80.45
+2020-07-19 02:00:00,14.02,0.0,-0.0,0.0,4.0,80.45
+2020-07-19 03:00:00,13.75,0.0,-0.0,0.0,4.07,86.35
+2020-07-19 04:00:00,13.45,29.0,0.0,29.0,3.86,92.65
+2020-07-19 05:00:00,13.52,67.0,0.0,67.0,3.66,89.45
+2020-07-19 06:00:00,14.0,286.0,228.64,188.0,3.52,86.4
+2020-07-19 07:00:00,14.94,446.0,375.22,232.0,2.97,89.5
+2020-07-19 08:00:00,16.61,663.0,731.14,157.0,3.52,78.0
+2020-07-19 09:00:00,17.95,753.0,711.63,194.0,3.72,70.35
+2020-07-19 10:00:00,19.03,654.0,320.97,383.0,4.07,61.3
+2020-07-19 11:00:00,19.79,105.0,0.0,105.0,4.0,61.4
+2020-07-19 12:00:00,19.68,279.0,1.18,278.0,4.14,59.25
+2020-07-19 13:00:00,18.91,303.0,7.63,297.0,4.34,61.2
+2020-07-19 14:00:00,18.63,448.0,167.44,332.0,4.34,63.4
+2020-07-19 15:00:00,18.95,469.0,448.17,213.0,4.41,63.4
+2020-07-19 16:00:00,19.23,268.0,172.25,194.0,4.21,63.5
+2020-07-19 17:00:00,18.02,135.0,75.65,114.0,4.76,63.4
+2020-07-19 18:00:00,17.19,74.0,223.02,46.0,3.66,70.3
+2020-07-19 19:00:00,16.73,0.0,-0.0,0.0,3.45,67.75
+2020-07-19 20:00:00,16.29,0.0,-0.0,0.0,3.66,67.65
+2020-07-19 21:00:00,15.89,0.0,-0.0,0.0,3.72,70.0
+2020-07-19 22:00:00,15.67,0.0,-0.0,0.0,3.66,70.0
+2020-07-19 23:00:00,15.18,0.0,-0.0,0.0,3.52,72.45
+2020-07-20 00:00:00,14.71,0.0,-0.0,0.0,3.31,75.0
+2020-07-20 01:00:00,14.35,0.0,-0.0,0.0,3.1,77.65
+2020-07-20 02:00:00,13.94,0.0,-0.0,0.0,2.83,80.4
+2020-07-20 03:00:00,13.5,0.0,-0.0,0.0,2.69,80.4
+2020-07-20 04:00:00,13.33,21.0,0.0,21.0,2.34,83.25
+2020-07-20 05:00:00,14.25,85.0,7.3,83.0,2.48,80.45
+2020-07-20 06:00:00,15.57,94.0,0.0,94.0,2.48,75.15
+2020-07-20 07:00:00,16.29,392.0,234.06,259.0,3.17,77.95
+2020-07-20 08:00:00,17.29,333.0,40.57,305.0,3.72,72.8
+2020-07-20 09:00:00,18.38,371.0,34.45,344.0,3.86,68.05
+2020-07-20 10:00:00,19.4,456.0,67.64,399.0,4.0,61.3
+2020-07-20 11:00:00,20.39,286.0,1.16,285.0,4.41,59.35
+2020-07-20 12:00:00,20.17,496.0,100.83,411.0,4.97,59.35
+2020-07-20 13:00:00,18.47,754.0,712.64,195.0,4.41,70.45
+2020-07-20 14:00:00,19.07,538.0,347.28,298.0,4.48,65.75
+2020-07-20 15:00:00,20.46,518.0,639.27,154.0,5.38,57.3
+2020-07-20 16:00:00,19.08,333.0,402.22,161.0,4.48,63.5
+2020-07-20 17:00:00,18.77,213.0,450.18,89.0,3.31,68.05
+2020-07-20 18:00:00,18.5,55.0,81.16,45.0,3.52,63.4
+2020-07-20 19:00:00,17.56,0.0,-0.0,0.0,3.17,67.95
+2020-07-20 20:00:00,16.89,0.0,-0.0,0.0,2.76,72.7
+2020-07-20 21:00:00,16.36,0.0,-0.0,0.0,2.41,72.65
+2020-07-20 22:00:00,15.68,0.0,-0.0,0.0,2.0,75.15
+2020-07-20 23:00:00,15.29,0.0,-0.0,0.0,2.0,77.8
+2020-07-21 00:00:00,14.64,0.0,-0.0,0.0,2.14,80.55
+2020-07-21 01:00:00,14.0,0.0,-0.0,0.0,2.07,83.4
+2020-07-21 02:00:00,13.73,0.0,-0.0,0.0,1.93,86.35
+2020-07-21 03:00:00,13.19,0.0,-0.0,0.0,1.93,86.3
+2020-07-21 04:00:00,12.7,33.0,8.39,32.0,1.86,89.4
+2020-07-21 05:00:00,14.24,63.0,0.0,63.0,1.52,86.4
+2020-07-21 06:00:00,16.62,170.0,21.23,161.0,1.38,78.0
+2020-07-21 07:00:00,18.73,261.0,37.1,240.0,1.59,75.55
+2020-07-21 08:00:00,20.07,388.0,91.55,325.0,1.79,68.3
+2020-07-21 09:00:00,21.11,270.0,2.56,268.0,2.83,59.6
+2020-07-21 10:00:00,21.74,535.0,146.27,412.0,3.24,53.75
+2020-07-21 11:00:00,22.16,609.0,224.11,416.0,2.76,52.0
+2020-07-21 12:00:00,23.06,0.0,0.0,0.0,2.62,50.3
+2020-07-21 13:00:00,23.86,0.0,0.0,0.0,2.28,47.15
+2020-07-21 14:00:00,24.37,0.0,0.0,0.0,1.93,47.25
+2020-07-21 15:00:00,24.86,182.0,1.76,181.0,2.07,47.4
+2020-07-21 16:00:00,24.67,246.0,129.24,191.0,2.0,49.05
+2020-07-21 17:00:00,23.4,185.0,285.51,107.0,0.9,71.25
+2020-07-21 18:00:00,23.3,74.0,264.97,42.0,0.48,68.85
+2020-07-21 19:00:00,21.72,0.0,-0.0,0.0,1.93,71.0
+2020-07-21 20:00:00,19.6,0.0,-0.0,0.0,2.07,78.35
+2020-07-21 21:00:00,18.65,0.0,-0.0,0.0,2.28,83.8
+2020-07-21 22:00:00,18.24,0.0,-0.0,0.0,2.41,81.0
+2020-07-21 23:00:00,18.18,0.0,-0.0,0.0,2.55,81.0
+2020-07-22 00:00:00,18.35,0.0,-0.0,0.0,2.55,83.8
+2020-07-22 01:00:00,18.25,0.0,-0.0,0.0,2.48,81.0
+2020-07-22 02:00:00,18.19,0.0,-0.0,0.0,2.07,83.8
+2020-07-22 03:00:00,17.99,0.0,-0.0,0.0,2.34,89.75
+2020-07-22 04:00:00,18.5,24.0,0.0,24.0,2.9,86.75
+2020-07-22 05:00:00,19.07,22.0,0.0,22.0,3.03,86.8
+2020-07-22 06:00:00,20.73,32.0,0.0,32.0,2.97,84.05
+2020-07-22 07:00:00,21.33,103.0,0.0,103.0,1.59,81.3
+2020-07-22 08:00:00,22.73,327.0,42.27,298.0,1.31,76.15
+2020-07-22 09:00:00,25.28,350.0,26.92,329.0,2.48,66.95
+2020-07-22 10:00:00,27.15,594.0,237.15,395.0,2.62,60.9
+2020-07-22 11:00:00,27.11,271.0,1.16,270.0,3.17,60.9
+2020-07-22 12:00:00,24.55,254.0,0.0,254.0,2.97,73.85
+2020-07-22 13:00:00,23.91,105.0,0.0,105.0,2.21,76.3
+2020-07-22 14:00:00,24.75,225.0,2.91,223.0,1.59,73.95
+2020-07-22 15:00:00,26.0,421.0,328.91,235.0,2.07,67.05
+2020-07-22 16:00:00,26.19,105.0,0.0,105.0,1.86,62.8
+2020-07-22 17:00:00,25.39,171.0,228.91,109.0,1.1,69.25
+2020-07-22 18:00:00,24.26,67.0,203.01,43.0,1.24,76.35
+2020-07-22 19:00:00,22.57,0.0,-0.0,0.0,2.0,84.25
+2020-07-22 20:00:00,21.34,0.0,-0.0,0.0,2.21,89.95
+2020-07-22 21:00:00,20.54,0.0,-0.0,0.0,2.28,86.9
+2020-07-22 22:00:00,20.07,0.0,-0.0,0.0,2.34,86.85
+2020-07-22 23:00:00,19.76,0.0,-0.0,0.0,2.41,86.85
+2020-07-23 00:00:00,19.54,0.0,-0.0,0.0,2.48,81.1
+2020-07-23 01:00:00,19.12,0.0,-0.0,0.0,2.55,81.05
+2020-07-23 02:00:00,18.94,0.0,-0.0,0.0,2.69,81.0
+2020-07-23 03:00:00,19.08,0.0,-0.0,0.0,2.83,78.3
+2020-07-23 04:00:00,19.56,52.0,96.9,41.0,2.97,75.7
+2020-07-23 05:00:00,20.77,51.0,0.0,51.0,2.9,75.85
+2020-07-23 06:00:00,22.44,222.0,93.06,183.0,2.48,73.55
+2020-07-23 07:00:00,24.29,433.0,377.51,221.0,3.1,69.05
+2020-07-23 08:00:00,26.16,340.0,51.17,305.0,3.31,62.8
+2020-07-23 09:00:00,27.85,112.0,0.0,112.0,3.31,57.05
+2020-07-23 10:00:00,28.78,129.0,0.0,129.0,3.52,53.55
+2020-07-23 11:00:00,29.46,453.0,62.96,399.0,3.38,55.4
+2020-07-23 12:00:00,29.68,645.0,328.23,370.0,3.03,55.5
+2020-07-23 13:00:00,28.82,366.0,34.65,339.0,1.1,63.3
+2020-07-23 14:00:00,30.81,411.0,126.91,324.0,2.28,53.9
+2020-07-23 15:00:00,27.31,46.0,0.0,46.0,3.24,63.0
+2020-07-23 16:00:00,26.24,265.0,189.95,185.0,2.41,67.15
+2020-07-23 17:00:00,26.09,165.0,208.64,109.0,3.72,64.8
+2020-07-23 18:00:00,24.32,18.0,0.0,18.0,4.62,64.5
+2020-07-23 19:00:00,23.57,0.0,-0.0,0.0,3.72,68.95
+2020-07-23 20:00:00,21.07,0.0,-0.0,0.0,3.86,81.3
+2020-07-23 21:00:00,20.21,0.0,-0.0,0.0,3.59,83.95
+2020-07-23 22:00:00,19.58,0.0,-0.0,0.0,3.45,86.85
+2020-07-23 23:00:00,19.09,0.0,-0.0,0.0,3.38,86.8
+2020-07-24 00:00:00,18.79,0.0,-0.0,0.0,3.45,86.75
+2020-07-24 01:00:00,18.27,0.0,-0.0,0.0,3.38,83.8
+2020-07-24 02:00:00,17.9,0.0,-0.0,0.0,3.38,86.7
+2020-07-24 03:00:00,17.61,0.0,-0.0,0.0,3.31,86.7
+2020-07-24 04:00:00,17.61,38.0,27.12,35.0,3.52,83.75
+2020-07-24 05:00:00,17.5,142.0,125.21,109.0,3.72,86.65
+2020-07-24 06:00:00,17.29,326.0,427.28,148.0,3.79,89.7
+2020-07-24 07:00:00,17.94,348.0,159.14,259.0,3.79,86.7
+2020-07-24 08:00:00,19.13,506.0,297.71,303.0,3.45,83.85
+2020-07-24 09:00:00,20.29,555.0,247.41,363.0,3.24,81.15
+2020-07-24 10:00:00,21.06,670.0,374.68,357.0,3.24,75.95
+2020-07-24 11:00:00,22.09,332.0,8.18,325.0,3.45,71.05
+2020-07-24 12:00:00,22.43,529.0,144.74,408.0,3.93,68.7
+2020-07-24 13:00:00,21.87,251.0,1.29,250.0,3.86,66.25
+2020-07-24 14:00:00,21.96,219.0,1.46,218.0,4.21,59.7
+2020-07-24 15:00:00,22.11,334.0,131.85,260.0,4.07,52.0
+2020-07-24 16:00:00,21.91,285.0,250.71,180.0,3.03,55.65
+2020-07-24 17:00:00,21.57,181.0,300.91,101.0,2.62,55.65
+2020-07-24 18:00:00,20.78,62.0,186.12,41.0,2.69,57.45
+2020-07-24 19:00:00,18.48,0.0,-0.0,0.0,2.83,70.45
+2020-07-24 20:00:00,17.63,0.0,-0.0,0.0,2.21,70.35
+2020-07-24 21:00:00,17.29,0.0,-0.0,0.0,2.07,72.8
+2020-07-24 22:00:00,16.93,0.0,-0.0,0.0,2.07,75.3
+2020-07-24 23:00:00,16.57,0.0,-0.0,0.0,2.21,75.3
+2020-07-25 00:00:00,16.08,0.0,-0.0,0.0,2.21,77.95
+2020-07-25 01:00:00,15.7,0.0,-0.0,0.0,2.0,83.55
+2020-07-25 02:00:00,14.99,0.0,-0.0,0.0,1.93,86.5
+2020-07-25 03:00:00,14.48,0.0,-0.0,0.0,2.07,86.45
+2020-07-25 04:00:00,14.62,6.0,0.0,6.0,2.41,86.45
+2020-07-25 05:00:00,15.37,21.0,0.0,21.0,2.76,86.5
+2020-07-25 06:00:00,15.13,93.0,0.0,93.0,3.59,83.5
+2020-07-25 07:00:00,14.1,226.0,16.16,217.0,4.41,89.5
+2020-07-25 08:00:00,14.15,382.0,89.75,321.0,4.41,89.5
+2020-07-25 09:00:00,15.31,637.0,409.56,320.0,3.86,86.5
+2020-07-25 10:00:00,17.61,391.0,31.2,365.0,4.69,67.95
+2020-07-25 11:00:00,18.64,590.0,200.26,419.0,5.17,61.2
+2020-07-25 12:00:00,18.83,591.0,224.21,404.0,5.52,61.2
+2020-07-25 13:00:00,18.78,767.0,783.02,160.0,5.79,59.05
+2020-07-25 14:00:00,18.59,59.0,0.0,59.0,5.93,56.95
+2020-07-25 15:00:00,18.33,295.0,73.35,254.0,5.59,54.95
+2020-07-25 16:00:00,18.21,73.0,0.0,73.0,5.24,54.95
+2020-07-25 17:00:00,18.0,154.0,163.37,111.0,4.9,56.85
+2020-07-25 18:00:00,17.07,69.0,281.87,38.0,4.48,63.2
+2020-07-25 19:00:00,15.85,0.0,-0.0,0.0,4.21,70.0
+2020-07-25 20:00:00,15.56,0.0,-0.0,0.0,3.93,72.55
+2020-07-25 21:00:00,15.2,0.0,-0.0,0.0,3.79,75.1
+2020-07-25 22:00:00,14.97,0.0,-0.0,0.0,3.86,77.75
+2020-07-25 23:00:00,14.64,0.0,-0.0,0.0,3.79,77.75
+2020-07-26 00:00:00,14.39,0.0,-0.0,0.0,3.59,80.45
+2020-07-26 01:00:00,14.17,0.0,-0.0,0.0,3.38,80.45
+2020-07-26 02:00:00,13.76,0.0,-0.0,0.0,3.17,80.4
+2020-07-26 03:00:00,13.38,0.0,-0.0,0.0,3.1,83.25
+2020-07-26 04:00:00,12.94,31.0,9.56,30.0,3.03,86.25
+2020-07-26 05:00:00,13.29,124.0,69.77,106.0,2.76,86.3
+2020-07-26 06:00:00,14.1,262.0,184.71,186.0,3.79,80.45
+2020-07-26 07:00:00,14.36,327.0,119.02,261.0,3.72,86.4
+2020-07-26 08:00:00,15.59,582.0,484.16,254.0,3.79,72.55
+2020-07-26 09:00:00,16.7,582.0,286.31,361.0,3.79,63.05
+2020-07-26 10:00:00,17.74,710.0,447.43,338.0,4.62,54.85
+2020-07-26 11:00:00,18.11,581.0,184.29,424.0,4.48,51.15
+2020-07-26 12:00:00,18.25,746.0,533.62,302.0,4.48,51.15
+2020-07-26 13:00:00,18.25,753.0,725.62,192.0,3.79,51.15
+2020-07-26 14:00:00,19.11,639.0,664.01,188.0,4.0,49.45
+2020-07-26 15:00:00,19.08,464.0,458.1,209.0,3.45,49.45
+2020-07-26 16:00:00,19.11,361.0,582.37,120.0,3.17,49.45
+2020-07-26 17:00:00,18.77,133.0,92.14,109.0,2.28,54.95
+2020-07-26 18:00:00,17.54,66.0,270.95,37.0,1.24,67.95
+2020-07-26 19:00:00,18.43,0.0,-0.0,0.0,0.62,54.95
+2020-07-26 20:00:00,16.84,0.0,-0.0,0.0,1.03,63.05
+2020-07-26 21:00:00,13.2,0.0,-0.0,0.0,1.93,80.35
+2020-07-26 22:00:00,12.41,0.0,-0.0,0.0,2.0,86.2
+2020-07-26 23:00:00,12.32,0.0,-0.0,0.0,2.0,86.2
+2020-07-27 00:00:00,12.53,0.0,-0.0,0.0,2.07,83.25
+2020-07-27 01:00:00,12.57,0.0,-0.0,0.0,2.14,83.25
+2020-07-27 02:00:00,12.29,0.0,-0.0,0.0,2.28,83.15
+2020-07-27 03:00:00,12.18,0.0,-0.0,0.0,2.34,83.15
+2020-07-27 04:00:00,12.22,59.0,236.24,35.0,2.41,80.2
+2020-07-27 05:00:00,13.66,203.0,493.81,77.0,2.28,77.6
+2020-07-27 06:00:00,16.11,366.0,638.44,105.0,2.14,70.1
+2020-07-27 07:00:00,18.35,507.0,661.15,142.0,2.55,65.65
+2020-07-27 08:00:00,20.0,557.0,426.55,269.0,3.03,61.4
+2020-07-27 09:00:00,21.36,762.0,783.36,159.0,3.31,57.55
+2020-07-27 10:00:00,22.45,842.0,828.36,155.0,3.72,53.85
+2020-07-27 11:00:00,23.25,897.0,913.06,121.0,3.86,48.7
+2020-07-27 12:00:00,23.92,873.0,906.04,121.0,3.86,48.8
+2020-07-27 13:00:00,24.44,801.0,881.98,121.0,3.86,48.95
+2020-07-27 14:00:00,24.8,684.0,831.69,121.0,3.72,47.4
+2020-07-27 15:00:00,24.99,536.0,756.03,117.0,3.52,49.05
+2020-07-27 16:00:00,24.9,370.0,642.03,106.0,3.1,49.05
+2020-07-27 17:00:00,24.17,205.0,485.19,80.0,2.41,56.25
+2020-07-27 18:00:00,22.64,61.0,240.43,36.0,2.41,62.05
+2020-07-27 19:00:00,20.95,0.0,-0.0,0.0,2.62,61.6
+2020-07-27 20:00:00,19.75,0.0,-0.0,0.0,2.76,63.6
+2020-07-27 21:00:00,18.99,0.0,-0.0,0.0,2.9,65.65
+2020-07-27 22:00:00,18.4,0.0,-0.0,0.0,2.83,65.65
+2020-07-27 23:00:00,17.84,0.0,-0.0,0.0,2.41,67.95
+2020-07-28 00:00:00,16.8,0.0,-0.0,0.0,2.07,75.3
+2020-07-28 01:00:00,16.64,0.0,-0.0,0.0,2.28,75.3
+2020-07-28 02:00:00,17.12,0.0,-0.0,0.0,2.83,75.4
+2020-07-28 03:00:00,17.02,0.0,-0.0,0.0,2.97,80.85
+2020-07-28 04:00:00,16.76,5.0,0.0,5.0,2.83,86.6
+2020-07-28 05:00:00,16.74,57.0,0.0,57.0,2.9,89.65
+2020-07-28 06:00:00,16.74,36.0,0.0,36.0,3.1,89.65
+2020-07-28 07:00:00,17.6,62.0,0.0,62.0,3.38,80.9
+2020-07-28 08:00:00,17.52,106.0,0.0,106.0,3.31,80.9
+2020-07-28 09:00:00,17.8,529.0,208.45,369.0,3.24,78.15
+2020-07-28 10:00:00,18.59,145.0,0.0,145.0,3.24,70.45
+2020-07-28 11:00:00,19.87,625.0,265.4,400.0,3.59,63.6
+2020-07-28 12:00:00,20.51,724.0,508.54,303.0,3.72,59.35
+2020-07-28 13:00:00,20.91,522.0,196.42,371.0,3.72,55.45
+2020-07-28 14:00:00,20.82,414.0,134.9,323.0,3.38,53.5
+2020-07-28 15:00:00,20.75,225.0,18.13,215.0,3.1,53.5
+2020-07-28 16:00:00,20.61,294.0,306.02,169.0,2.9,53.5
+2020-07-28 17:00:00,20.1,189.0,400.48,87.0,2.34,53.35
+2020-07-28 18:00:00,19.06,56.0,198.35,36.0,1.66,61.3
+2020-07-28 19:00:00,18.1,0.0,-0.0,0.0,1.1,68.05
+2020-07-28 20:00:00,18.89,0.0,-0.0,0.0,0.48,59.05
+2020-07-28 21:00:00,16.69,0.0,-0.0,0.0,1.31,65.35
+2020-07-28 22:00:00,14.2,0.0,-0.0,0.0,1.79,77.65
+2020-07-28 23:00:00,13.18,0.0,-0.0,0.0,1.86,83.25
+2020-07-29 00:00:00,12.55,0.0,-0.0,0.0,1.86,86.25
+2020-07-29 01:00:00,12.26,0.0,-0.0,0.0,1.86,89.35
+2020-07-29 02:00:00,11.81,0.0,-0.0,0.0,1.86,89.3
+2020-07-29 03:00:00,11.44,0.0,-0.0,0.0,1.93,92.55
+2020-07-29 04:00:00,11.24,38.0,62.94,32.0,1.86,92.55
+2020-07-29 05:00:00,13.19,190.0,433.17,82.0,1.52,89.4
+2020-07-29 06:00:00,17.42,346.0,565.2,118.0,1.24,78.1
+2020-07-29 07:00:00,19.65,503.0,661.73,141.0,1.38,70.65
+2020-07-29 08:00:00,21.13,639.0,706.94,165.0,1.93,57.55
+2020-07-29 09:00:00,21.93,716.0,641.57,225.0,2.21,53.75
+2020-07-29 10:00:00,22.62,769.0,621.78,256.0,2.28,50.3
+2020-07-29 11:00:00,23.29,860.0,826.6,161.0,2.21,47.0
+2020-07-29 12:00:00,23.55,827.0,795.73,170.0,2.28,47.0
+2020-07-29 13:00:00,24.25,741.0,716.26,192.0,2.34,44.05
+2020-07-29 14:00:00,24.4,612.0,599.58,209.0,2.34,44.05
+2020-07-29 15:00:00,24.59,518.0,708.47,129.0,2.48,42.65
+2020-07-29 16:00:00,24.39,350.0,569.46,119.0,2.34,45.6
+2020-07-29 17:00:00,23.61,177.0,321.87,96.0,1.86,54.2
+2020-07-29 18:00:00,22.09,43.0,92.23,34.0,2.07,59.8
+2020-07-29 19:00:00,20.41,0.0,-0.0,0.0,2.48,63.7
+2020-07-29 20:00:00,19.32,0.0,-0.0,0.0,2.55,68.1
+2020-07-29 21:00:00,18.57,0.0,-0.0,0.0,2.55,68.05
+2020-07-29 22:00:00,17.94,0.0,-0.0,0.0,2.62,70.35
+2020-07-29 23:00:00,17.44,0.0,-0.0,0.0,2.83,67.85
+2020-07-30 00:00:00,17.05,0.0,-0.0,0.0,2.97,65.45
+2020-07-30 01:00:00,16.73,0.0,-0.0,0.0,3.17,67.75
+2020-07-30 02:00:00,16.6,0.0,-0.0,0.0,3.38,67.75
+2020-07-30 03:00:00,16.45,0.0,-0.0,0.0,3.52,72.65
+2020-07-30 04:00:00,16.25,47.0,151.95,33.0,3.45,75.25
+2020-07-30 05:00:00,16.81,190.0,454.64,78.0,3.45,75.3
+2020-07-30 06:00:00,18.43,310.0,401.86,149.0,3.24,72.95
+2020-07-30 07:00:00,20.74,194.0,5.51,191.0,3.31,68.4
+2020-07-30 08:00:00,22.49,322.0,40.41,295.0,3.17,66.35
+2020-07-30 09:00:00,24.09,729.0,695.92,198.0,3.86,62.35
+2020-07-30 10:00:00,24.5,442.0,64.41,389.0,4.97,56.25
+2020-07-30 11:00:00,24.43,729.0,474.27,329.0,5.31,52.5
+2020-07-30 12:00:00,24.31,692.0,429.93,338.0,5.1,50.7
+2020-07-30 13:00:00,24.34,582.0,304.93,349.0,4.97,48.95
+2020-07-30 14:00:00,24.13,491.0,274.78,307.0,4.62,47.25
+2020-07-30 15:00:00,23.47,322.0,120.8,256.0,4.14,50.45
+2020-07-30 16:00:00,22.76,195.0,57.11,172.0,3.72,50.3
+2020-07-30 17:00:00,21.61,66.0,0.0,66.0,3.52,51.9
+2020-07-30 18:00:00,20.42,31.0,21.22,29.0,3.1,55.3
+2020-07-30 19:00:00,19.72,0.0,-0.0,0.0,2.41,53.25
+2020-07-30 20:00:00,18.37,0.0,-0.0,0.0,1.93,59.05
+2020-07-30 21:00:00,16.54,0.0,-0.0,0.0,1.93,65.35
+2020-07-30 22:00:00,15.46,0.0,-0.0,0.0,1.86,72.45
+2020-07-30 23:00:00,14.48,0.0,-0.0,0.0,1.79,75.0
+2020-07-31 00:00:00,13.61,0.0,-0.0,0.0,1.86,77.6
+2020-07-31 01:00:00,13.0,0.0,-0.0,0.0,1.79,80.35
+2020-07-31 02:00:00,12.42,0.0,-0.0,0.0,1.93,83.15
+2020-07-31 03:00:00,12.64,0.0,-0.0,0.0,2.21,80.3
+2020-07-31 04:00:00,12.96,9.0,0.0,9.0,2.34,77.5
+2020-07-31 05:00:00,13.86,100.0,36.99,91.0,2.0,80.4
+2020-07-31 06:00:00,15.68,118.0,2.51,117.0,2.0,70.0
+2020-07-31 07:00:00,16.31,228.0,22.15,216.0,2.14,72.65
+2020-07-31 08:00:00,17.28,439.0,178.78,320.0,2.07,67.85
+2020-07-31 09:00:00,18.2,712.0,641.54,224.0,2.14,61.2
+2020-07-31 10:00:00,18.97,710.0,474.08,321.0,2.07,59.05
+2020-07-31 11:00:00,19.26,686.0,379.25,367.0,1.86,55.05
+2020-07-31 12:00:00,20.0,737.0,539.56,294.0,1.79,53.25
+2020-07-31 13:00:00,20.33,615.0,375.5,329.0,1.86,49.7
+2020-07-31 14:00:00,20.53,391.0,106.44,320.0,1.66,47.9
+2020-07-31 15:00:00,20.37,322.0,121.42,256.0,1.79,47.9
+2020-07-31 16:00:00,16.45,306.0,375.26,156.0,1.59,57.83
+2020-07-31 17:00:00,16.68,180.0,375.06,88.0,1.64,59.33
+2020-07-31 18:00:00,16.9,35.0,55.07,30.0,1.69,60.82
+2020-07-31 19:00:00,17.13,0.0,-0.0,0.0,1.74,62.31
+2020-07-31 20:00:00,17.36,0.0,-0.0,0.0,1.8,63.8
+2020-07-31 21:00:00,17.58,0.0,-0.0,0.0,1.85,65.3
+2020-07-31 22:00:00,17.81,0.0,-0.0,0.0,1.9,66.79
+2020-07-31 23:00:00,18.04,0.0,-0.0,0.0,1.95,68.28
+2020-08-01 00:00:00,18.26,0.0,-0.0,0.0,2.0,69.78
+2020-08-01 01:00:00,18.49,0.0,-0.0,0.0,2.06,71.27
+2020-08-01 02:00:00,18.71,0.0,-0.0,0.0,2.11,72.76
+2020-08-01 03:00:00,18.94,0.0,-0.0,0.0,2.16,74.26
+2020-08-01 04:00:00,19.17,30.0,48.62,26.0,2.21,75.75
+2020-08-01 05:00:00,19.39,158.0,299.38,87.0,2.26,77.24
+2020-08-01 06:00:00,19.62,325.0,540.7,113.0,2.32,78.74
+2020-08-01 07:00:00,19.84,484.0,665.41,127.0,2.37,80.23
+2020-08-01 08:00:00,25.97,632.0,756.92,132.0,2.28,56.6
+2020-08-01 09:00:00,27.51,741.0,797.79,138.0,2.34,51.45
+2020-08-01 10:00:00,28.73,816.0,832.32,137.0,2.41,46.65
+2020-08-01 11:00:00,29.53,840.0,840.54,137.0,2.28,43.65
+2020-08-01 12:00:00,30.09,812.0,820.92,142.0,2.0,38.3
+2020-08-01 13:00:00,30.61,73.0,0.0,73.0,1.86,35.85
+2020-08-01 14:00:00,30.64,70.0,0.0,70.0,1.52,35.85
+2020-08-01 15:00:00,29.67,195.0,7.44,191.0,2.41,38.15
+2020-08-01 16:00:00,27.19,285.0,330.43,155.0,3.24,46.4
+2020-08-01 17:00:00,25.82,132.0,142.53,98.0,2.14,58.55
+2020-08-01 18:00:00,24.87,35.0,83.72,28.0,1.66,66.85
+2020-08-01 19:00:00,23.38,0.0,-0.0,0.0,2.55,73.7
+2020-08-01 20:00:00,21.48,0.0,-0.0,0.0,2.0,86.95
+2020-08-01 21:00:00,20.66,0.0,-0.0,0.0,1.45,89.9
+2020-08-01 22:00:00,20.39,0.0,-0.0,0.0,1.66,92.95
+2020-08-01 23:00:00,20.02,0.0,-0.0,0.0,1.79,89.85
+2020-08-02 00:00:00,19.8,0.0,-0.0,0.0,1.93,89.85
+2020-08-02 01:00:00,19.63,0.0,-0.0,0.0,2.34,89.85
+2020-08-02 02:00:00,19.26,0.0,-0.0,0.0,2.48,92.9
+2020-08-02 03:00:00,18.63,0.0,-0.0,0.0,2.07,92.85
+2020-08-02 04:00:00,18.38,9.0,0.0,9.0,1.93,96.05
+2020-08-02 05:00:00,18.43,27.0,0.0,27.0,1.93,99.4
+2020-08-02 06:00:00,18.84,32.0,0.0,32.0,2.9,96.1
+2020-08-02 07:00:00,18.72,96.0,0.0,96.0,1.93,96.1
+2020-08-02 08:00:00,18.6,135.0,0.0,135.0,1.79,96.1
+2020-08-02 09:00:00,18.53,241.0,1.33,240.0,2.21,96.1
+2020-08-02 10:00:00,18.67,345.0,18.44,330.0,2.0,96.1
+2020-08-02 11:00:00,19.01,196.0,0.0,196.0,1.93,92.9
+2020-08-02 12:00:00,20.44,247.0,0.0,247.0,1.24,92.95
+2020-08-02 13:00:00,20.69,162.0,0.0,162.0,1.45,89.9
+2020-08-02 14:00:00,20.86,282.0,22.77,267.0,1.52,86.9
+2020-08-02 15:00:00,21.02,305.0,114.09,244.0,1.17,84.05
+2020-08-02 16:00:00,21.05,271.0,287.08,159.0,0.9,81.3
+2020-08-02 17:00:00,20.97,137.0,178.7,95.0,0.55,78.5
+2020-08-02 18:00:00,20.68,38.0,137.7,27.0,0.76,78.5
+2020-08-02 19:00:00,19.23,0.0,-0.0,0.0,0.83,89.8
+2020-08-02 20:00:00,17.97,0.0,-0.0,0.0,1.31,92.85
+2020-08-02 21:00:00,17.18,0.0,-0.0,0.0,1.59,92.85
+2020-08-02 22:00:00,16.55,0.0,-0.0,0.0,1.79,92.8
+2020-08-02 23:00:00,16.58,0.0,-0.0,0.0,1.86,92.8
+2020-08-03 00:00:00,16.61,0.0,-0.0,0.0,1.93,92.8
+2020-08-03 01:00:00,17.17,0.0,-0.0,0.0,2.0,92.85
+2020-08-03 02:00:00,17.44,0.0,-0.0,0.0,2.0,92.85
+2020-08-03 03:00:00,17.94,0.0,-0.0,0.0,2.07,92.85
+2020-08-03 04:00:00,17.88,33.0,105.98,25.0,2.14,86.65
+2020-08-03 05:00:00,18.49,114.0,90.98,93.0,2.34,78.25
+2020-08-03 06:00:00,19.69,185.0,59.56,162.0,2.69,73.15
+2020-08-03 07:00:00,20.49,497.0,726.95,111.0,3.59,70.8
+2020-08-03 08:00:00,21.39,435.0,193.79,308.0,4.14,70.9
+2020-08-03 09:00:00,22.36,359.0,38.63,330.0,4.21,66.35
+2020-08-03 10:00:00,23.22,568.0,223.23,387.0,4.34,60.05
+2020-08-03 11:00:00,23.81,323.0,8.42,316.0,4.55,56.15
+2020-08-03 12:00:00,24.2,506.0,136.87,395.0,4.83,52.5
+2020-08-03 13:00:00,24.49,126.0,0.0,126.0,4.9,52.5
+2020-08-03 14:00:00,24.57,210.0,1.52,209.0,4.48,49.05
+2020-08-03 15:00:00,24.19,276.0,71.5,238.0,3.93,50.7
+2020-08-03 16:00:00,24.1,113.0,2.59,112.0,3.72,50.7
+2020-08-03 17:00:00,23.44,129.0,146.92,95.0,3.03,56.0
+2020-08-03 18:00:00,22.4,34.0,105.19,26.0,2.34,59.8
+2020-08-03 19:00:00,21.31,0.0,-0.0,0.0,1.86,63.9
+2020-08-03 20:00:00,19.59,0.0,-0.0,0.0,2.0,73.15
+2020-08-03 21:00:00,18.25,0.0,-0.0,0.0,2.07,78.15
+2020-08-03 22:00:00,17.51,0.0,-0.0,0.0,2.14,80.85
+2020-08-03 23:00:00,17.03,0.0,-0.0,0.0,2.21,80.85
+2020-08-04 00:00:00,16.88,0.0,-0.0,0.0,2.34,86.6
+2020-08-04 01:00:00,17.34,0.0,-0.0,0.0,2.55,83.7
+2020-08-04 02:00:00,17.56,0.0,-0.0,0.0,2.9,83.7
+2020-08-04 03:00:00,18.16,0.0,-0.0,0.0,3.31,80.9
+2020-08-04 04:00:00,18.72,4.0,0.0,4.0,3.72,78.25
+2020-08-04 05:00:00,19.77,25.0,0.0,25.0,4.34,75.7
+2020-08-04 06:00:00,21.15,121.0,2.61,120.0,3.93,70.9
+2020-08-04 07:00:00,21.98,81.0,0.0,81.0,3.79,73.45
+2020-08-04 08:00:00,20.87,332.0,56.69,295.0,5.59,73.3
+2020-08-04 09:00:00,19.71,130.0,0.0,130.0,4.21,86.85
+2020-08-04 10:00:00,18.22,444.0,74.23,384.0,4.48,89.75
+2020-08-04 11:00:00,18.59,695.0,438.0,332.0,4.21,78.25
+2020-08-04 12:00:00,20.82,554.0,200.42,392.0,5.59,63.8
+2020-08-04 13:00:00,22.09,674.0,584.02,237.0,6.28,53.85
+2020-08-04 14:00:00,22.06,522.0,393.72,265.0,5.59,52.0
+2020-08-04 15:00:00,21.71,474.0,628.48,142.0,5.45,53.75
+2020-08-04 16:00:00,21.12,334.0,615.72,98.0,4.69,55.55
+2020-08-04 17:00:00,20.54,160.0,338.14,83.0,4.34,57.45
+2020-08-04 18:00:00,20.05,34.0,138.63,24.0,4.28,53.35
+2020-08-04 19:00:00,19.31,0.0,-0.0,0.0,3.24,53.15
+2020-08-04 20:00:00,18.42,0.0,-0.0,0.0,2.76,54.85
+2020-08-04 21:00:00,17.52,0.0,-0.0,0.0,2.76,56.75
+2020-08-04 22:00:00,16.8,0.0,-0.0,0.0,2.9,58.7
+2020-08-04 23:00:00,16.39,0.0,-0.0,0.0,3.17,60.75
+2020-08-05 00:00:00,16.12,0.0,-0.0,0.0,3.38,62.95
+2020-08-05 01:00:00,15.68,0.0,-0.0,0.0,3.45,67.55
+2020-08-05 02:00:00,15.41,0.0,-0.0,0.0,3.52,69.9
+2020-08-05 03:00:00,15.07,0.0,-0.0,0.0,3.79,69.9
+2020-08-05 04:00:00,14.88,36.0,204.23,22.0,4.0,72.4
+2020-08-05 05:00:00,15.14,176.0,485.83,67.0,4.34,72.45
+2020-08-05 06:00:00,16.09,333.0,618.18,98.0,4.28,70.1
+2020-08-05 07:00:00,17.52,493.0,711.96,119.0,6.41,70.3
+2020-08-05 08:00:00,18.15,610.0,681.59,167.0,6.48,65.55
+2020-08-05 09:00:00,18.71,653.0,513.7,270.0,6.55,63.4
+2020-08-05 10:00:00,19.39,465.0,90.61,392.0,6.69,61.3
+2020-08-05 11:00:00,19.86,741.0,543.51,292.0,6.55,57.2
+2020-08-05 12:00:00,20.81,618.0,305.39,372.0,6.76,53.5
+2020-08-05 13:00:00,21.34,278.0,5.37,274.0,6.55,49.95
+2020-08-05 14:00:00,21.43,566.0,521.83,227.0,6.0,48.2
+2020-08-05 15:00:00,21.41,348.0,196.22,245.0,5.38,48.2
+2020-08-05 16:00:00,21.16,230.0,155.38,171.0,4.55,48.2
+2020-08-05 17:00:00,20.74,148.0,267.96,88.0,3.52,49.8
+2020-08-05 18:00:00,19.84,31.0,117.43,23.0,2.83,51.4
+2020-08-05 19:00:00,18.72,0.0,-0.0,0.0,2.83,54.95
+2020-08-05 20:00:00,17.75,0.0,-0.0,0.0,2.34,60.95
+2020-08-05 21:00:00,16.64,0.0,-0.0,0.0,2.21,63.05
+2020-08-05 22:00:00,15.74,0.0,-0.0,0.0,2.21,67.55
+2020-08-05 23:00:00,14.83,0.0,-0.0,0.0,2.07,72.4
+2020-08-06 00:00:00,13.82,0.0,-0.0,0.0,1.93,80.4
+2020-08-06 01:00:00,13.09,0.0,-0.0,0.0,1.86,80.35
+2020-08-06 02:00:00,12.51,0.0,-0.0,0.0,1.72,83.25
+2020-08-06 03:00:00,12.26,0.0,-0.0,0.0,1.66,86.2
+2020-08-06 04:00:00,11.93,3.0,0.0,3.0,1.59,86.2
+2020-08-06 05:00:00,12.89,148.0,298.55,82.0,1.24,89.4
+2020-08-06 06:00:00,16.31,296.0,437.58,131.0,0.9,77.95
+2020-08-06 07:00:00,18.59,263.0,61.25,231.0,1.17,70.45
+2020-08-06 08:00:00,20.17,242.0,7.73,237.0,0.97,61.5
+2020-08-06 09:00:00,21.22,555.0,290.76,339.0,0.48,55.55
+2020-08-06 10:00:00,22.16,746.0,636.38,235.0,0.28,52.0
+2020-08-06 11:00:00,22.81,829.0,829.51,146.0,0.55,48.55
+2020-08-06 12:00:00,23.93,813.0,844.64,135.0,0.34,45.5
+2020-08-06 13:00:00,24.07,746.0,833.83,127.0,0.28,44.05
+2020-08-06 14:00:00,24.06,621.0,750.26,136.0,1.24,45.6
+2020-08-06 15:00:00,24.07,462.0,602.09,148.0,1.86,45.6
+2020-08-06 16:00:00,23.79,313.0,531.82,113.0,2.21,48.8
+2020-08-06 17:00:00,23.14,150.0,309.05,82.0,1.93,54.1
+2020-08-06 18:00:00,21.83,24.0,62.48,20.0,2.07,59.7
+2020-08-06 19:00:00,20.92,0.0,-0.0,0.0,2.48,59.5
+2020-08-06 20:00:00,19.68,0.0,-0.0,0.0,2.41,63.6
+2020-08-06 21:00:00,18.65,0.0,-0.0,0.0,2.34,65.65
+2020-08-06 22:00:00,18.06,0.0,-0.0,0.0,2.34,67.95
+2020-08-06 23:00:00,17.57,0.0,-0.0,0.0,2.48,67.85
+2020-08-07 00:00:00,17.16,0.0,-0.0,0.0,2.55,65.45
+2020-08-07 01:00:00,16.87,0.0,-0.0,0.0,2.69,65.35
+2020-08-07 02:00:00,16.79,0.0,-0.0,0.0,2.76,63.05
+2020-08-07 03:00:00,16.72,0.0,-0.0,0.0,2.9,63.05
+2020-08-07 04:00:00,16.71,30.0,178.96,19.0,2.97,63.05
+2020-08-07 05:00:00,17.23,167.0,468.44,65.0,2.83,65.45
+2020-08-07 06:00:00,19.14,333.0,647.12,91.0,2.69,65.75
+2020-08-07 07:00:00,21.3,486.0,712.25,116.0,3.1,61.7
+2020-08-07 08:00:00,23.09,638.0,806.98,118.0,3.24,56.0
+2020-08-07 09:00:00,24.71,736.0,805.26,140.0,3.45,49.05
+2020-08-07 10:00:00,26.16,802.0,817.25,148.0,3.72,44.55
+2020-08-07 11:00:00,27.34,849.0,882.29,125.0,3.79,40.35
+2020-08-07 12:00:00,28.36,829.0,886.47,120.0,3.93,39.1
+2020-08-07 13:00:00,29.07,121.0,0.0,121.0,4.0,36.7
+2020-08-07 14:00:00,29.51,645.0,831.81,110.0,4.07,35.45
+2020-08-07 15:00:00,29.67,484.0,704.62,119.0,4.0,35.6
+2020-08-07 16:00:00,29.32,319.0,580.14,103.0,3.31,39.35
+2020-08-07 17:00:00,28.2,139.0,245.32,86.0,2.76,43.4
+2020-08-07 18:00:00,26.22,25.0,100.29,19.0,2.69,47.75
+2020-08-07 19:00:00,24.79,0.0,-0.0,0.0,3.17,49.05
+2020-08-07 20:00:00,24.13,0.0,-0.0,0.0,3.38,50.7
+2020-08-07 21:00:00,23.76,0.0,-0.0,0.0,3.17,56.15
+2020-08-07 22:00:00,23.0,0.0,-0.0,0.0,2.76,62.05
+2020-08-07 23:00:00,22.04,0.0,-0.0,0.0,2.21,66.35
+2020-08-08 00:00:00,21.19,0.0,-0.0,0.0,1.93,73.35
+2020-08-08 01:00:00,20.32,0.0,-0.0,0.0,1.93,78.45
+2020-08-08 02:00:00,19.16,0.0,-0.0,0.0,1.86,86.8
+2020-08-08 03:00:00,18.67,0.0,-0.0,0.0,1.52,89.75
+2020-08-08 04:00:00,18.34,2.0,0.0,2.0,1.38,92.85
+2020-08-08 05:00:00,18.27,35.0,0.0,35.0,1.31,96.05
+2020-08-08 06:00:00,19.52,256.0,283.16,151.0,1.66,86.85
+2020-08-08 07:00:00,19.47,453.0,606.0,140.0,2.34,86.8
+2020-08-08 08:00:00,20.27,588.0,665.6,161.0,3.31,81.15
+2020-08-08 09:00:00,21.33,640.0,524.85,253.0,3.38,75.95
+2020-08-08 10:00:00,22.55,641.0,387.48,332.0,3.1,68.75
+2020-08-08 11:00:00,23.62,363.0,23.23,344.0,3.45,60.15
+2020-08-08 12:00:00,24.24,722.0,599.88,244.0,3.79,54.35
+2020-08-08 13:00:00,24.49,225.0,0.0,225.0,4.14,50.7
+2020-08-08 14:00:00,23.73,379.0,120.35,302.0,4.34,48.8
+2020-08-08 15:00:00,22.93,484.0,734.81,106.0,4.83,52.1
+2020-08-08 16:00:00,21.94,299.0,499.34,115.0,4.07,57.65
+2020-08-08 17:00:00,21.24,113.0,127.37,86.0,3.31,61.7
+2020-08-08 18:00:00,20.46,20.0,54.01,17.0,2.9,68.3
+2020-08-08 19:00:00,19.8,0.0,-0.0,0.0,3.59,61.4
+2020-08-08 20:00:00,19.23,0.0,-0.0,0.0,3.59,63.5
+2020-08-08 21:00:00,18.57,0.0,-0.0,0.0,3.38,65.65
+2020-08-08 22:00:00,18.12,0.0,-0.0,0.0,3.45,67.95
+2020-08-08 23:00:00,17.71,0.0,-0.0,0.0,3.59,70.3
+2020-08-09 00:00:00,17.31,0.0,-0.0,0.0,3.52,70.3
+2020-08-09 01:00:00,16.78,0.0,-0.0,0.0,3.72,75.3
+2020-08-09 02:00:00,16.22,0.0,-0.0,0.0,3.72,77.95
+2020-08-09 03:00:00,15.35,0.0,-0.0,0.0,4.28,86.5
+2020-08-09 04:00:00,14.97,20.0,55.3,17.0,4.07,86.5
+2020-08-09 05:00:00,14.54,30.0,0.0,30.0,3.86,86.45
+2020-08-09 06:00:00,14.53,169.0,46.24,152.0,3.93,83.45
+2020-08-09 07:00:00,14.82,221.0,25.32,208.0,4.14,86.45
+2020-08-09 08:00:00,15.47,412.0,164.41,307.0,4.48,77.85
+2020-08-09 09:00:00,16.07,452.0,126.61,359.0,4.41,72.65
+2020-08-09 10:00:00,17.22,123.0,0.0,123.0,4.69,60.95
+2020-08-09 11:00:00,17.98,110.0,0.0,110.0,4.97,54.85
+2020-08-09 12:00:00,18.61,203.0,0.0,203.0,5.17,49.3
+2020-08-09 13:00:00,18.91,142.0,0.0,142.0,5.03,47.55
+2020-08-09 14:00:00,19.19,495.0,345.71,275.0,4.83,44.3
+2020-08-09 15:00:00,18.98,372.0,287.82,225.0,4.21,42.7
+2020-08-09 16:00:00,18.95,284.0,411.45,134.0,4.07,44.2
+2020-08-09 17:00:00,18.58,136.0,264.66,81.0,3.38,44.2
+2020-08-09 18:00:00,17.95,19.0,58.62,16.0,2.55,49.05
+2020-08-09 19:00:00,16.65,0.0,-0.0,0.0,1.1,60.85
+2020-08-09 20:00:00,15.31,0.0,-0.0,0.0,1.17,69.9
+2020-08-09 21:00:00,14.04,0.0,-0.0,0.0,1.52,72.3
+2020-08-09 22:00:00,12.75,0.0,-0.0,0.0,1.66,80.3
+2020-08-09 23:00:00,12.27,0.0,-0.0,0.0,1.72,83.15
+2020-08-10 00:00:00,11.87,0.0,-0.0,0.0,1.79,83.1
+2020-08-10 01:00:00,11.35,0.0,-0.0,0.0,1.93,86.1
+2020-08-10 02:00:00,11.33,0.0,-0.0,0.0,2.07,86.1
+2020-08-10 03:00:00,11.25,0.0,-0.0,0.0,2.21,83.05
+2020-08-10 04:00:00,11.28,8.0,0.0,8.0,2.21,83.05
+2020-08-10 05:00:00,12.58,58.0,4.82,57.0,2.21,80.3
+2020-08-10 06:00:00,15.62,144.0,21.95,136.0,2.14,70.0
+2020-08-10 07:00:00,18.2,345.0,229.21,228.0,2.83,70.35
+2020-08-10 08:00:00,19.79,508.0,402.71,252.0,3.17,68.2
+2020-08-10 09:00:00,21.23,619.0,475.65,271.0,3.59,59.6
+2020-08-10 10:00:00,21.93,351.0,22.74,333.0,3.45,55.65
+2020-08-10 11:00:00,22.62,311.0,7.39,305.0,2.9,52.1
+2020-08-10 12:00:00,23.94,272.0,2.53,270.0,3.1,48.8
+2020-08-10 13:00:00,23.88,224.0,0.0,224.0,2.41,50.55
+2020-08-10 14:00:00,23.65,170.0,0.0,170.0,1.72,54.2
+2020-08-10 15:00:00,23.07,160.0,1.97,159.0,1.79,58.0
+2020-08-10 16:00:00,22.07,132.0,13.87,127.0,2.41,59.8
+2020-08-10 17:00:00,21.2,83.0,39.3,75.0,1.45,66.15
+2020-08-10 18:00:00,20.97,12.0,21.4,11.0,0.28,68.4
+2020-08-10 19:00:00,18.63,0.0,-0.0,0.0,1.45,86.75
+2020-08-10 20:00:00,17.89,0.0,-0.0,0.0,1.66,89.7
+2020-08-10 21:00:00,17.19,0.0,-0.0,0.0,1.79,86.65
+2020-08-10 22:00:00,17.29,0.0,-0.0,0.0,1.72,83.7
+2020-08-10 23:00:00,17.75,0.0,-0.0,0.0,2.0,83.7
+2020-08-11 00:00:00,17.34,0.0,-0.0,0.0,1.79,86.65
+2020-08-11 01:00:00,17.08,0.0,-0.0,0.0,1.86,86.65
+2020-08-11 02:00:00,16.74,0.0,-0.0,0.0,1.93,86.6
+2020-08-11 03:00:00,16.26,0.0,-0.0,0.0,2.07,89.65
+2020-08-11 04:00:00,16.3,2.0,0.0,2.0,2.14,89.65
+2020-08-11 05:00:00,16.64,113.0,156.77,81.0,2.07,86.6
+2020-08-11 06:00:00,17.31,199.0,116.29,157.0,1.93,86.65
+2020-08-11 07:00:00,19.57,385.0,362.66,201.0,1.72,78.35
+2020-08-11 08:00:00,21.67,582.0,674.87,155.0,2.28,68.6
+2020-08-11 09:00:00,23.16,631.0,522.86,250.0,2.97,62.15
+2020-08-11 10:00:00,24.17,392.0,45.64,356.0,3.1,58.2
+2020-08-11 11:00:00,25.13,615.0,311.57,363.0,3.03,52.75
+2020-08-11 12:00:00,24.99,231.0,0.0,231.0,2.83,52.6
+2020-08-11 13:00:00,24.8,517.0,247.85,337.0,2.28,54.45
+2020-08-11 14:00:00,25.21,577.0,662.69,160.0,1.66,52.75
+2020-08-11 15:00:00,25.15,200.0,15.9,192.0,1.24,54.55
+2020-08-11 16:00:00,24.86,292.0,521.81,106.0,0.69,56.35
+2020-08-11 17:00:00,23.11,141.0,376.44,66.0,0.55,66.55
+2020-08-11 18:00:00,21.76,15.0,47.42,13.0,0.97,76.0
+2020-08-11 19:00:00,21.68,0.0,-0.0,0.0,1.72,64.0
+2020-08-11 20:00:00,20.46,0.0,-0.0,0.0,1.72,73.2
+2020-08-11 21:00:00,19.22,0.0,-0.0,0.0,1.17,83.85
+2020-08-11 22:00:00,18.61,0.0,-0.0,0.0,0.97,86.75
+2020-08-11 23:00:00,18.19,0.0,-0.0,0.0,0.83,89.75
+2020-08-12 00:00:00,18.42,0.0,-0.0,0.0,0.34,89.75
+2020-08-12 01:00:00,17.25,0.0,-0.0,0.0,0.83,92.85
+2020-08-12 02:00:00,17.22,0.0,-0.0,0.0,1.72,92.85
+2020-08-12 03:00:00,17.42,0.0,-0.0,0.0,2.14,92.85
+2020-08-12 04:00:00,17.25,1.0,0.0,1.0,2.41,89.7
+2020-08-12 05:00:00,17.6,21.0,0.0,21.0,2.48,92.85
+2020-08-12 06:00:00,19.06,251.0,310.14,140.0,2.41,89.8
+2020-08-12 07:00:00,19.67,408.0,468.03,172.0,3.17,83.9
+2020-08-12 08:00:00,21.32,509.0,436.72,234.0,3.93,75.95
+2020-08-12 09:00:00,23.08,528.0,278.35,326.0,4.83,64.3
+2020-08-12 10:00:00,24.33,258.0,1.27,257.0,5.1,58.2
+2020-08-12 11:00:00,25.45,133.0,0.0,133.0,4.69,54.55
+2020-08-12 12:00:00,24.8,140.0,0.0,140.0,3.86,60.35
+2020-08-12 13:00:00,23.81,117.0,0.0,117.0,2.62,71.35
+2020-08-12 14:00:00,23.59,65.0,0.0,65.0,2.14,73.75
+2020-08-12 15:00:00,23.67,83.0,0.0,83.0,3.03,71.35
+2020-08-12 16:00:00,22.61,54.0,0.0,54.0,2.9,76.15
+2020-08-12 17:00:00,21.8,12.0,0.0,12.0,3.52,78.65
+2020-08-12 18:00:00,21.27,10.0,0.0,10.0,4.07,75.95
+2020-08-12 19:00:00,20.22,0.0,-0.0,0.0,2.55,81.15
+2020-08-12 20:00:00,19.75,0.0,-0.0,0.0,1.93,81.1
+2020-08-12 21:00:00,19.45,0.0,-0.0,0.0,1.86,83.85
+2020-08-12 22:00:00,19.24,0.0,-0.0,0.0,2.76,78.3
+2020-08-12 23:00:00,18.6,0.0,-0.0,0.0,3.31,78.25
+2020-08-13 00:00:00,17.63,0.0,-0.0,0.0,3.1,83.7
+2020-08-13 01:00:00,17.34,0.0,-0.0,0.0,2.76,83.7
+2020-08-13 02:00:00,17.04,0.0,-0.0,0.0,2.97,83.7
+2020-08-13 03:00:00,16.77,0.0,-0.0,0.0,3.31,80.8
+2020-08-13 04:00:00,16.6,12.0,0.0,12.0,3.52,78.0
+2020-08-13 05:00:00,16.52,13.0,0.0,13.0,3.66,75.3
+2020-08-13 06:00:00,16.82,138.0,19.74,131.0,3.59,78.0
+2020-08-13 07:00:00,17.79,275.0,91.8,229.0,3.38,78.1
+2020-08-13 08:00:00,19.62,629.0,836.22,105.0,4.21,65.85
+2020-08-13 09:00:00,20.83,540.0,290.59,330.0,4.69,55.45
+2020-08-13 10:00:00,21.51,704.0,563.45,263.0,4.83,50.05
+2020-08-13 11:00:00,21.89,566.0,220.55,389.0,5.17,48.3
+2020-08-13 12:00:00,22.63,767.0,767.06,168.0,5.24,45.25
+2020-08-13 13:00:00,22.7,594.0,421.26,291.0,4.9,43.65
+2020-08-13 14:00:00,23.19,532.0,496.94,223.0,5.17,40.75
+2020-08-13 15:00:00,23.22,420.0,512.95,166.0,4.62,39.3
+2020-08-13 16:00:00,22.99,299.0,589.09,94.0,3.79,42.1
+2020-08-13 17:00:00,22.35,133.0,346.81,67.0,3.1,45.1
+2020-08-13 18:00:00,20.79,9.0,0.0,9.0,2.28,48.05
+2020-08-13 19:00:00,19.24,0.0,-0.0,0.0,2.0,59.15
+2020-08-13 20:00:00,17.95,0.0,-0.0,0.0,2.0,65.45
+2020-08-13 21:00:00,16.76,0.0,-0.0,0.0,2.14,67.75
+2020-08-13 22:00:00,15.86,0.0,-0.0,0.0,2.28,72.55
+2020-08-13 23:00:00,15.01,0.0,-0.0,0.0,2.21,75.1
+2020-08-14 00:00:00,14.38,0.0,-0.0,0.0,2.34,77.65
+2020-08-14 01:00:00,14.05,0.0,-0.0,0.0,2.48,77.65
+2020-08-14 02:00:00,13.87,0.0,-0.0,0.0,2.55,77.6
+2020-08-14 03:00:00,13.67,0.0,-0.0,0.0,2.55,77.6
+2020-08-14 04:00:00,13.44,9.0,0.0,9.0,2.48,77.6
+2020-08-14 05:00:00,14.03,132.0,330.59,68.0,2.41,77.65
+2020-08-14 06:00:00,16.74,114.0,5.69,112.0,2.21,70.2
+2020-08-14 07:00:00,18.81,272.0,90.38,227.0,2.83,70.45
+2020-08-14 08:00:00,20.06,588.0,697.65,153.0,2.9,61.5
+2020-08-14 09:00:00,21.13,556.0,325.18,322.0,2.83,55.55
+2020-08-14 10:00:00,22.13,566.0,248.86,372.0,2.83,50.2
+2020-08-14 11:00:00,22.9,667.0,421.62,330.0,3.24,46.85
+2020-08-14 12:00:00,23.73,626.0,370.41,338.0,3.59,42.35
+2020-08-14 13:00:00,24.11,654.0,598.05,226.0,3.03,41.0
+2020-08-14 14:00:00,23.66,422.0,210.37,292.0,2.21,43.9
+2020-08-14 15:00:00,23.45,284.0,112.0,229.0,1.66,47.0
+2020-08-14 16:00:00,23.01,93.0,0.0,93.0,1.03,54.1
+2020-08-14 17:00:00,22.26,77.0,43.08,69.0,0.69,66.35
+2020-08-14 18:00:00,21.27,8.0,0.0,8.0,1.24,63.9
+2020-08-14 19:00:00,20.03,0.0,-0.0,0.0,1.59,61.5
+2020-08-14 20:00:00,18.88,0.0,-0.0,0.0,1.59,68.05
+2020-08-14 21:00:00,17.93,0.0,-0.0,0.0,1.59,70.3
+2020-08-14 22:00:00,17.25,0.0,-0.0,0.0,1.72,67.85
+2020-08-14 23:00:00,16.98,0.0,-0.0,0.0,1.79,67.85
+2020-08-15 00:00:00,16.57,0.0,-0.0,0.0,1.59,72.7
+2020-08-15 01:00:00,16.0,0.0,-0.0,0.0,1.66,77.95
+2020-08-15 02:00:00,15.35,0.0,-0.0,0.0,2.21,86.5
+2020-08-15 03:00:00,14.71,0.0,-0.0,0.0,2.83,89.5
+2020-08-15 04:00:00,14.24,1.0,0.0,1.0,3.17,89.5
+2020-08-15 05:00:00,14.04,17.0,0.0,17.0,3.17,89.5
+2020-08-15 06:00:00,13.93,32.0,0.0,32.0,3.17,89.5
+2020-08-15 07:00:00,14.19,62.0,0.0,62.0,3.24,92.7
+2020-08-15 08:00:00,14.27,68.0,0.0,68.0,3.93,92.7
+2020-08-15 09:00:00,14.71,102.0,0.0,102.0,4.34,92.7
+2020-08-15 10:00:00,14.32,96.0,0.0,96.0,4.9,92.7
+2020-08-15 11:00:00,14.24,108.0,0.0,108.0,4.34,92.7
+2020-08-15 12:00:00,14.12,91.0,0.0,91.0,4.28,92.7
+2020-08-15 13:00:00,13.98,87.0,0.0,87.0,4.41,92.7
+2020-08-15 14:00:00,13.74,88.0,0.0,88.0,4.55,92.65
+2020-08-15 15:00:00,13.65,50.0,0.0,50.0,4.62,92.65
+2020-08-15 16:00:00,13.56,41.0,0.0,41.0,4.76,89.45
+2020-08-15 17:00:00,13.32,25.0,0.0,25.0,4.28,92.65
+2020-08-15 18:00:00,13.05,2.0,0.0,2.0,3.59,89.4
+2020-08-15 19:00:00,12.69,0.0,-0.0,0.0,3.59,92.6
+2020-08-15 20:00:00,12.48,0.0,-0.0,0.0,3.24,92.6
+2020-08-15 21:00:00,12.25,0.0,-0.0,0.0,3.03,92.6
+2020-08-15 22:00:00,12.1,0.0,-0.0,0.0,2.76,92.6
+2020-08-15 23:00:00,11.9,0.0,-0.0,0.0,2.69,92.6
+2020-08-16 00:00:00,11.64,0.0,-0.0,0.0,2.62,95.9
+2020-08-16 01:00:00,11.57,0.0,-0.0,0.0,2.34,99.4
+2020-08-16 02:00:00,11.49,0.0,-0.0,0.0,2.07,99.4
+2020-08-16 03:00:00,11.48,0.0,-0.0,0.0,2.21,99.4
+2020-08-16 04:00:00,11.63,1.0,0.0,1.0,2.41,99.4
+2020-08-16 05:00:00,11.87,71.0,32.18,65.0,2.9,99.4
+2020-08-16 06:00:00,12.26,108.0,2.9,107.0,3.52,99.4
+2020-08-16 07:00:00,12.71,89.0,0.0,89.0,2.55,99.4
+2020-08-16 08:00:00,13.15,95.0,0.0,95.0,2.69,99.4
+2020-08-16 09:00:00,13.56,138.0,0.0,138.0,3.79,95.95
+2020-08-16 10:00:00,14.09,162.0,0.0,162.0,3.31,92.7
+2020-08-16 11:00:00,14.46,91.0,0.0,91.0,3.17,89.5
+2020-08-16 12:00:00,14.42,69.0,0.0,69.0,2.97,92.7
+2020-08-16 13:00:00,14.63,86.0,0.0,86.0,2.9,92.7
+2020-08-16 14:00:00,14.81,97.0,0.0,97.0,2.76,89.5
+2020-08-16 15:00:00,14.97,109.0,0.0,109.0,2.83,86.5
+2020-08-16 16:00:00,14.87,168.0,74.7,143.0,2.69,89.5
+2020-08-16 17:00:00,14.67,95.0,141.81,70.0,2.41,89.5
+2020-08-16 18:00:00,14.43,0.0,0.0,0.0,2.21,89.5
+2020-08-16 19:00:00,13.93,0.0,-0.0,0.0,2.48,89.5
+2020-08-16 20:00:00,13.74,0.0,-0.0,0.0,2.28,92.65
+2020-08-16 21:00:00,13.45,0.0,-0.0,0.0,2.21,92.65
+2020-08-16 22:00:00,13.28,0.0,-0.0,0.0,2.21,95.95
+2020-08-16 23:00:00,13.05,0.0,-0.0,0.0,2.21,92.65
+2020-08-17 00:00:00,12.33,0.0,-0.0,0.0,2.28,92.6
+2020-08-17 01:00:00,12.06,0.0,-0.0,0.0,2.28,89.35
+2020-08-17 02:00:00,11.71,0.0,-0.0,0.0,2.41,92.55
+2020-08-17 03:00:00,11.42,0.0,-0.0,0.0,2.41,89.3
+2020-08-17 04:00:00,11.13,1.0,0.0,1.0,2.34,92.55
+2020-08-17 05:00:00,11.67,65.0,21.88,61.0,2.28,89.3
+2020-08-17 06:00:00,13.39,189.0,114.36,150.0,2.0,89.4
+2020-08-17 07:00:00,15.46,455.0,702.73,112.0,2.83,83.55
+2020-08-17 08:00:00,16.97,599.0,770.41,126.0,3.24,75.4
+2020-08-17 09:00:00,18.33,696.0,764.72,153.0,3.72,65.55
+2020-08-17 10:00:00,19.28,757.0,757.3,174.0,3.66,57.1
+2020-08-17 11:00:00,19.79,784.0,779.24,169.0,3.31,53.25
+2020-08-17 12:00:00,20.3,719.0,640.24,228.0,3.03,51.5
+2020-08-17 13:00:00,20.71,672.0,692.8,184.0,2.97,48.05
+2020-08-17 14:00:00,20.91,563.0,656.83,165.0,2.9,46.35
+2020-08-17 15:00:00,20.71,403.0,495.54,166.0,2.48,46.35
+2020-08-17 16:00:00,20.42,265.0,463.53,112.0,1.79,51.5
+2020-08-17 17:00:00,19.56,64.0,23.33,60.0,1.24,63.6
+2020-08-17 18:00:00,18.95,0.0,0.0,0.0,0.83,63.4
+2020-08-17 19:00:00,17.79,0.0,-0.0,0.0,1.24,67.85
+2020-08-17 20:00:00,15.83,0.0,-0.0,0.0,1.86,75.15
+2020-08-17 21:00:00,14.66,0.0,-0.0,0.0,1.86,80.55
+2020-08-17 22:00:00,13.85,0.0,-0.0,0.0,1.93,83.35
+2020-08-17 23:00:00,13.42,0.0,-0.0,0.0,2.0,83.35
+2020-08-18 00:00:00,12.79,0.0,-0.0,0.0,2.14,86.25
+2020-08-18 01:00:00,12.5,0.0,-0.0,0.0,2.14,86.25
+2020-08-18 02:00:00,12.47,0.0,-0.0,0.0,2.28,83.25
+2020-08-18 03:00:00,12.42,0.0,-0.0,0.0,2.34,83.25
+2020-08-18 04:00:00,12.04,0.0,0.0,0.0,2.48,83.15
+2020-08-18 05:00:00,12.57,91.0,117.21,70.0,2.41,80.3
+2020-08-18 06:00:00,15.58,210.0,189.59,146.0,2.21,75.15
+2020-08-18 07:00:00,18.49,389.0,433.2,179.0,3.03,70.45
+2020-08-18 08:00:00,20.15,498.0,429.02,236.0,3.17,68.3
+2020-08-18 09:00:00,21.64,629.0,561.7,232.0,3.17,61.85
+2020-08-18 10:00:00,22.46,716.0,652.32,216.0,4.0,57.75
+2020-08-18 11:00:00,22.92,562.0,237.99,375.0,4.14,54.0
+2020-08-18 12:00:00,23.3,642.0,448.1,300.0,4.0,52.25
+2020-08-18 13:00:00,23.69,264.0,7.14,259.0,3.86,48.8
+2020-08-18 14:00:00,24.0,575.0,742.8,128.0,3.45,50.55
+2020-08-18 15:00:00,23.65,451.0,744.97,98.0,2.48,54.2
+2020-08-18 16:00:00,23.55,272.0,556.24,91.0,2.28,56.15
+2020-08-18 17:00:00,22.62,51.0,12.01,49.0,1.79,59.95
+2020-08-18 18:00:00,20.99,0.0,0.0,0.0,1.86,66.15
+2020-08-18 19:00:00,19.11,0.0,-0.0,0.0,2.0,73.05
+2020-08-18 20:00:00,17.75,0.0,-0.0,0.0,2.07,80.85
+2020-08-18 21:00:00,16.76,0.0,-0.0,0.0,2.14,80.8
+2020-08-18 22:00:00,16.36,0.0,-0.0,0.0,2.14,83.6
+2020-08-18 23:00:00,15.8,0.0,-0.0,0.0,2.28,83.55
+2020-08-19 00:00:00,15.6,0.0,-0.0,0.0,2.34,83.55
+2020-08-19 01:00:00,15.61,0.0,-0.0,0.0,2.41,80.65
+2020-08-19 02:00:00,15.57,0.0,-0.0,0.0,2.48,80.65
+2020-08-19 03:00:00,15.65,0.0,-0.0,0.0,2.62,77.85
+2020-08-19 04:00:00,15.89,0.0,0.0,0.0,2.69,77.85
+2020-08-19 05:00:00,16.37,38.0,0.0,38.0,2.69,77.95
+2020-08-19 06:00:00,18.24,98.0,2.99,97.0,2.55,75.45
+2020-08-19 07:00:00,20.88,420.0,608.65,127.0,2.9,70.8
+2020-08-19 08:00:00,22.84,461.0,339.16,255.0,3.38,64.2
+2020-08-19 09:00:00,24.33,451.0,163.48,336.0,3.59,60.25
+2020-08-19 10:00:00,25.61,659.0,509.77,270.0,3.72,56.6
+2020-08-19 11:00:00,26.56,647.0,432.12,309.0,3.79,54.95
+2020-08-19 12:00:00,27.34,610.0,389.74,314.0,3.66,51.45
+2020-08-19 13:00:00,27.53,139.0,0.0,139.0,3.24,53.2
+2020-08-19 14:00:00,27.53,68.0,0.0,68.0,2.83,53.2
+2020-08-19 15:00:00,27.11,205.0,31.96,190.0,2.48,53.2
+2020-08-19 16:00:00,24.97,274.0,592.57,84.0,1.45,71.5
+2020-08-19 17:00:00,23.84,24.0,0.0,24.0,0.62,76.3
+2020-08-19 18:00:00,21.91,0.0,0.0,0.0,1.66,84.1
+2020-08-19 19:00:00,20.33,0.0,-0.0,0.0,1.52,92.95
+2020-08-19 20:00:00,19.35,0.0,-0.0,0.0,0.97,96.1
+2020-08-19 21:00:00,18.75,0.0,-0.0,0.0,0.48,99.4
+2020-08-19 22:00:00,18.55,0.0,-0.0,0.0,0.28,96.1
+2020-08-19 23:00:00,17.36,0.0,-0.0,0.0,1.03,96.05
+2020-08-20 00:00:00,17.84,0.0,-0.0,0.0,1.72,99.4
+2020-08-20 01:00:00,18.06,0.0,-0.0,0.0,2.55,92.85
+2020-08-20 02:00:00,17.46,0.0,-0.0,0.0,2.97,89.7
+2020-08-20 03:00:00,16.74,0.0,-0.0,0.0,2.97,89.65
+2020-08-20 04:00:00,16.06,0.0,0.0,0.0,2.9,89.65
+2020-08-20 05:00:00,15.75,24.0,0.0,24.0,2.97,92.75
+2020-08-20 06:00:00,16.46,267.0,502.17,101.0,2.62,86.6
+2020-08-20 07:00:00,17.55,423.0,612.98,130.0,3.17,83.7
+2020-08-20 08:00:00,19.07,560.0,677.12,151.0,3.79,73.05
+2020-08-20 09:00:00,20.25,579.0,432.8,276.0,4.62,63.7
+2020-08-20 10:00:00,20.98,513.0,190.88,368.0,4.69,59.5
+2020-08-20 11:00:00,21.49,597.0,313.39,353.0,4.83,55.65
+2020-08-20 12:00:00,21.66,102.0,0.0,102.0,4.9,53.75
+2020-08-20 13:00:00,21.55,198.0,0.0,198.0,4.69,53.75
+2020-08-20 14:00:00,21.51,217.0,6.74,213.0,4.34,53.75
+2020-08-20 15:00:00,21.33,418.0,647.66,117.0,3.93,55.55
+2020-08-20 16:00:00,21.0,196.0,186.83,137.0,3.59,55.55
+2020-08-20 17:00:00,20.36,92.0,198.07,61.0,2.97,59.35
+2020-08-20 18:00:00,19.45,0.0,-0.0,0.0,2.83,61.3
+2020-08-20 19:00:00,18.51,0.0,-0.0,0.0,2.28,63.4
+2020-08-20 20:00:00,17.58,0.0,-0.0,0.0,2.41,67.85
+2020-08-20 21:00:00,17.18,0.0,-0.0,0.0,2.55,67.85
+2020-08-20 22:00:00,16.91,0.0,-0.0,0.0,2.76,70.2
+2020-08-20 23:00:00,16.81,0.0,-0.0,0.0,2.97,70.2
+2020-08-21 00:00:00,16.35,0.0,-0.0,0.0,2.9,72.65
+2020-08-21 01:00:00,16.09,0.0,-0.0,0.0,2.9,72.65
+2020-08-21 02:00:00,15.59,0.0,-0.0,0.0,2.83,75.15
+2020-08-21 03:00:00,15.31,0.0,-0.0,0.0,2.69,77.8
+2020-08-21 04:00:00,14.87,0.0,0.0,0.0,2.41,80.55
+2020-08-21 05:00:00,14.75,115.0,351.02,56.0,2.21,83.45
+2020-08-21 06:00:00,15.85,282.0,599.36,86.0,2.07,80.65
+2020-08-21 07:00:00,17.1,431.0,659.57,118.0,2.83,75.4
+2020-08-21 08:00:00,18.31,572.0,727.56,135.0,3.1,70.35
+2020-08-21 09:00:00,19.36,589.0,457.89,270.0,3.17,63.5
+2020-08-21 10:00:00,20.21,660.0,503.89,279.0,3.1,59.35
+2020-08-21 11:00:00,20.7,741.0,690.4,206.0,3.03,55.45
+2020-08-21 12:00:00,21.19,633.0,441.61,301.0,2.62,53.6
+2020-08-21 13:00:00,21.61,659.0,711.88,169.0,2.62,51.9
+2020-08-21 14:00:00,21.77,526.0,579.12,185.0,2.55,50.05
+2020-08-21 15:00:00,21.65,368.0,417.31,176.0,2.0,51.9
+2020-08-21 16:00:00,21.39,144.0,51.47,128.0,1.45,57.55
+2020-08-21 17:00:00,20.42,82.0,145.33,60.0,0.83,75.75
+2020-08-21 18:00:00,20.2,0.0,-0.0,0.0,0.76,65.95
+2020-08-21 19:00:00,20.32,0.0,-0.0,0.0,0.62,59.35
+2020-08-21 20:00:00,17.62,0.0,-0.0,0.0,1.31,75.4
+2020-08-21 21:00:00,15.98,0.0,-0.0,0.0,1.59,77.95
+2020-08-21 22:00:00,14.69,0.0,-0.0,0.0,1.72,86.45
+2020-08-21 23:00:00,13.78,0.0,-0.0,0.0,1.86,89.45
+2020-08-22 00:00:00,13.18,0.0,-0.0,0.0,1.93,89.4
+2020-08-22 01:00:00,13.03,0.0,-0.0,0.0,1.93,86.3
+2020-08-22 02:00:00,12.75,0.0,-0.0,0.0,2.0,86.25
+2020-08-22 03:00:00,12.51,0.0,-0.0,0.0,1.93,86.25
+2020-08-22 04:00:00,12.17,0.0,0.0,0.0,1.86,86.2
+2020-08-22 05:00:00,12.27,52.0,12.17,50.0,1.66,89.35
+2020-08-22 06:00:00,15.52,258.0,479.22,103.0,1.17,83.55
+2020-08-22 07:00:00,18.6,383.0,458.52,167.0,0.97,75.55
+2020-08-22 08:00:00,20.12,378.0,157.4,284.0,1.03,65.95
+2020-08-22 09:00:00,21.33,609.0,536.64,237.0,1.45,63.9
+2020-08-22 10:00:00,22.27,648.0,487.68,281.0,1.72,57.75
+2020-08-22 11:00:00,22.91,759.0,775.44,161.0,1.66,55.9
+2020-08-22 12:00:00,23.4,713.0,696.67,192.0,1.72,52.25
+2020-08-22 13:00:00,23.89,660.0,744.02,151.0,2.14,48.8
+2020-08-22 14:00:00,23.97,505.0,527.07,197.0,2.28,47.15
+2020-08-22 15:00:00,23.95,287.0,171.3,209.0,2.28,47.15
+2020-08-22 16:00:00,23.39,52.0,0.0,52.0,1.66,54.1
+2020-08-22 17:00:00,22.43,64.0,61.57,55.0,1.66,61.95
+2020-08-22 18:00:00,20.95,0.0,-0.0,0.0,1.79,66.05
+2020-08-22 19:00:00,19.59,0.0,-0.0,0.0,1.93,73.15
+2020-08-22 20:00:00,18.2,0.0,-0.0,0.0,1.93,80.9
+2020-08-22 21:00:00,17.23,0.0,-0.0,0.0,1.86,86.65
+2020-08-22 22:00:00,16.89,0.0,-0.0,0.0,1.59,89.65
+2020-08-22 23:00:00,16.56,0.0,-0.0,0.0,1.31,89.65
+2020-08-23 00:00:00,16.49,0.0,-0.0,0.0,1.66,89.65
+2020-08-23 01:00:00,16.53,0.0,-0.0,0.0,1.93,86.6
+2020-08-23 02:00:00,16.45,0.0,-0.0,0.0,2.48,86.6
+2020-08-23 03:00:00,15.89,0.0,-0.0,0.0,3.03,92.75
+2020-08-23 04:00:00,15.62,0.0,0.0,0.0,3.31,89.6
+2020-08-23 05:00:00,15.5,35.0,0.0,35.0,4.07,89.6
+2020-08-23 06:00:00,15.09,87.0,0.0,87.0,4.62,89.55
+2020-08-23 07:00:00,14.78,376.0,434.15,173.0,5.1,86.45
+2020-08-23 08:00:00,15.09,351.0,116.22,282.0,4.9,83.5
+2020-08-23 09:00:00,15.78,641.0,648.12,194.0,4.97,80.65
+2020-08-23 10:00:00,16.95,610.0,391.23,317.0,4.97,67.85
+2020-08-23 11:00:00,17.77,676.0,517.34,279.0,4.9,63.2
+2020-08-23 12:00:00,18.26,668.0,557.93,253.0,4.55,58.9
+2020-08-23 13:00:00,18.68,660.0,748.7,151.0,4.28,54.95
+2020-08-23 14:00:00,18.96,484.0,457.04,219.0,4.14,53.0
+2020-08-23 15:00:00,18.94,322.0,277.44,197.0,4.0,51.15
+2020-08-23 16:00:00,18.52,237.0,452.07,101.0,3.45,49.3
+2020-08-23 17:00:00,17.89,87.0,241.3,53.0,2.48,52.75
+2020-08-23 18:00:00,16.59,0.0,-0.0,0.0,1.93,52.65
+2020-08-23 19:00:00,14.82,0.0,-0.0,0.0,2.0,62.65
+2020-08-23 20:00:00,13.44,0.0,-0.0,0.0,1.93,69.65
+2020-08-23 21:00:00,12.41,0.0,-0.0,0.0,2.0,72.05
+2020-08-23 22:00:00,11.88,0.0,-0.0,0.0,2.14,77.3
+2020-08-23 23:00:00,12.13,0.0,-0.0,0.0,2.34,74.6
+2020-08-24 00:00:00,11.98,0.0,-0.0,0.0,2.41,74.6
+2020-08-24 01:00:00,11.59,0.0,-0.0,0.0,2.48,77.3
+2020-08-24 02:00:00,11.69,0.0,-0.0,0.0,2.76,77.3
+2020-08-24 03:00:00,11.93,0.0,-0.0,0.0,3.1,74.6
+2020-08-24 04:00:00,12.34,0.0,-0.0,0.0,3.59,77.35
+2020-08-24 05:00:00,12.44,10.0,0.0,10.0,3.59,80.3
+2020-08-24 06:00:00,12.48,53.0,0.0,53.0,3.52,86.25
+2020-08-24 07:00:00,12.57,94.0,0.0,94.0,5.31,89.4
+2020-08-24 08:00:00,12.87,140.0,0.0,140.0,4.97,92.6
+2020-08-24 09:00:00,13.69,153.0,0.0,153.0,6.14,83.35
+2020-08-24 10:00:00,14.26,246.0,1.34,245.0,6.21,80.45
+2020-08-24 11:00:00,14.9,566.0,268.49,361.0,4.76,77.75
+2020-08-24 12:00:00,15.66,216.0,0.0,216.0,5.1,67.55
+2020-08-24 13:00:00,16.62,432.0,152.48,329.0,4.0,63.05
+2020-08-24 14:00:00,17.56,432.0,307.72,255.0,4.62,58.8
+2020-08-24 15:00:00,17.82,352.0,403.9,172.0,4.48,58.8
+2020-08-24 16:00:00,17.47,220.0,368.61,111.0,4.14,60.95
+2020-08-24 17:00:00,17.16,90.0,317.19,47.0,3.86,58.8
+2020-08-24 18:00:00,16.43,0.0,-0.0,0.0,3.31,62.95
+2020-08-24 19:00:00,15.29,0.0,-0.0,0.0,2.41,69.9
+2020-08-24 20:00:00,14.62,0.0,-0.0,0.0,2.14,72.4
+2020-08-24 21:00:00,13.77,0.0,-0.0,0.0,2.0,77.6
+2020-08-24 22:00:00,12.81,0.0,-0.0,0.0,1.86,83.25
+2020-08-24 23:00:00,11.69,0.0,-0.0,0.0,1.86,86.15
+2020-08-25 00:00:00,10.82,0.0,-0.0,0.0,1.86,89.25
+2020-08-25 01:00:00,10.42,0.0,-0.0,0.0,1.79,86.05
+2020-08-25 02:00:00,10.1,0.0,-0.0,0.0,1.72,89.2
+2020-08-25 03:00:00,9.83,0.0,-0.0,0.0,1.66,92.45
+2020-08-25 04:00:00,9.54,0.0,-0.0,0.0,1.66,92.45
+2020-08-25 05:00:00,9.92,62.0,45.76,55.0,1.52,92.5
+2020-08-25 06:00:00,12.52,204.0,233.56,131.0,1.24,89.4
+2020-08-25 07:00:00,16.13,368.0,427.83,171.0,1.24,80.75
+2020-08-25 08:00:00,17.07,385.0,185.8,276.0,1.38,78.1
+2020-08-25 09:00:00,17.43,253.0,5.86,249.0,1.45,75.4
+2020-08-25 10:00:00,17.49,215.0,0.0,215.0,1.31,75.4
+2020-08-25 11:00:00,17.59,279.0,5.27,275.0,1.45,75.4
+2020-08-25 12:00:00,17.68,433.0,103.32,357.0,1.72,75.4
+2020-08-25 13:00:00,17.2,338.0,50.66,304.0,1.17,78.1
+2020-08-25 14:00:00,16.91,202.0,5.26,199.0,1.24,86.6
+2020-08-25 15:00:00,17.27,146.0,4.54,144.0,1.24,83.7
+2020-08-25 16:00:00,17.36,116.0,24.1,109.0,1.24,83.7
+2020-08-25 17:00:00,17.1,59.0,76.83,49.0,1.24,83.7
+2020-08-25 18:00:00,16.49,0.0,-0.0,0.0,1.45,83.65
+2020-08-25 19:00:00,15.89,0.0,-0.0,0.0,1.24,89.6
+2020-08-25 20:00:00,14.14,0.0,-0.0,0.0,1.66,92.7
+2020-08-25 21:00:00,13.29,0.0,-0.0,0.0,1.79,92.65
+2020-08-25 22:00:00,13.1,0.0,-0.0,0.0,1.86,92.65
+2020-08-25 23:00:00,13.54,0.0,-0.0,0.0,2.07,89.45
+2020-08-26 00:00:00,13.76,0.0,-0.0,0.0,2.28,89.45
+2020-08-26 01:00:00,14.07,0.0,-0.0,0.0,2.28,89.5
+2020-08-26 02:00:00,14.23,0.0,-0.0,0.0,2.14,92.7
+2020-08-26 03:00:00,14.41,0.0,-0.0,0.0,2.21,92.7
+2020-08-26 04:00:00,14.54,0.0,-0.0,0.0,2.21,92.7
+2020-08-26 05:00:00,14.52,43.0,6.7,42.0,2.21,92.7
+2020-08-26 06:00:00,15.44,174.0,132.74,133.0,2.07,89.6
+2020-08-26 07:00:00,16.35,343.0,345.84,185.0,2.21,89.65
+2020-08-26 08:00:00,17.79,444.0,334.44,249.0,2.55,83.7
+2020-08-26 09:00:00,18.46,528.0,346.18,293.0,2.48,80.9
+2020-08-26 10:00:00,19.69,538.0,261.62,345.0,3.1,68.2
+2020-08-26 11:00:00,20.36,589.0,334.82,336.0,3.17,63.7
+2020-08-26 12:00:00,21.05,575.0,348.66,320.0,2.97,57.55
+2020-08-26 13:00:00,21.19,579.0,519.04,233.0,2.62,57.55
+2020-08-26 14:00:00,21.35,424.0,316.39,245.0,2.41,57.55
+2020-08-26 15:00:00,21.41,345.0,417.74,163.0,2.14,57.55
+2020-08-26 16:00:00,21.28,217.0,413.69,99.0,1.66,59.6
+2020-08-26 17:00:00,20.24,68.0,168.42,47.0,0.97,73.2
+2020-08-26 18:00:00,20.53,0.0,-0.0,0.0,0.28,61.6
+2020-08-26 19:00:00,17.34,0.0,-0.0,0.0,1.31,80.85
+2020-08-26 20:00:00,16.59,0.0,-0.0,0.0,1.31,80.8
+2020-08-26 21:00:00,15.62,0.0,-0.0,0.0,1.52,83.55
+2020-08-26 22:00:00,14.7,0.0,-0.0,0.0,1.66,89.5
+2020-08-26 23:00:00,14.19,0.0,-0.0,0.0,1.66,89.5
+2020-08-27 00:00:00,14.15,0.0,-0.0,0.0,1.52,92.7
+2020-08-27 01:00:00,13.98,0.0,-0.0,0.0,1.52,92.7
+2020-08-27 02:00:00,14.01,0.0,-0.0,0.0,1.45,92.7
+2020-08-27 03:00:00,14.09,0.0,-0.0,0.0,1.45,92.7
+2020-08-27 04:00:00,14.0,0.0,-0.0,0.0,1.38,92.7
+2020-08-27 05:00:00,14.3,42.0,6.88,41.0,1.17,96.0
+2020-08-27 06:00:00,16.28,153.0,78.65,129.0,0.76,89.65
+2020-08-27 07:00:00,18.62,259.0,116.94,206.0,1.1,81.0
+2020-08-27 08:00:00,19.84,287.0,51.78,257.0,1.72,73.15
+2020-08-27 09:00:00,20.81,480.0,245.88,314.0,2.48,68.4
+2020-08-27 10:00:00,21.35,545.0,282.07,338.0,2.62,66.15
+2020-08-27 11:00:00,21.88,718.0,707.84,186.0,2.55,61.85
+2020-08-27 12:00:00,22.63,711.0,771.56,150.0,2.69,57.9
+2020-08-27 13:00:00,23.25,661.0,821.67,117.0,2.76,54.1
+2020-08-27 14:00:00,23.77,529.0,720.23,125.0,2.69,52.35
+2020-08-27 15:00:00,23.78,375.0,587.57,122.0,2.34,52.35
+2020-08-27 16:00:00,23.2,220.0,464.44,90.0,1.72,58.0
+2020-08-27 17:00:00,22.16,69.0,209.8,44.0,1.31,66.35
+2020-08-27 18:00:00,22.16,0.0,-0.0,0.0,0.55,59.8
+2020-08-27 19:00:00,21.24,0.0,-0.0,0.0,0.69,63.9
+2020-08-27 20:00:00,17.3,0.0,-0.0,0.0,1.79,83.7
+2020-08-27 21:00:00,16.04,0.0,-0.0,0.0,2.0,86.55
+2020-08-27 22:00:00,15.17,0.0,-0.0,0.0,1.86,89.55
+2020-08-27 23:00:00,14.85,0.0,-0.0,0.0,1.72,92.7
+2020-08-28 00:00:00,15.26,0.0,-0.0,0.0,2.21,89.55
+2020-08-28 01:00:00,14.88,0.0,-0.0,0.0,2.0,92.7
+2020-08-28 02:00:00,14.44,0.0,-0.0,0.0,1.93,92.7
+2020-08-28 03:00:00,14.22,0.0,-0.0,0.0,1.66,96.0
+2020-08-28 04:00:00,14.53,0.0,-0.0,0.0,1.66,96.0
+2020-08-28 05:00:00,14.63,17.0,0.0,17.0,1.52,96.0
+2020-08-28 06:00:00,15.68,152.0,86.26,126.0,2.07,92.75
+2020-08-28 07:00:00,16.71,81.0,0.0,81.0,2.55,86.6
+2020-08-28 08:00:00,17.63,90.0,0.0,90.0,2.97,83.7
+2020-08-28 09:00:00,18.14,161.0,0.0,161.0,3.1,80.9
+2020-08-28 10:00:00,18.26,190.0,0.0,190.0,3.24,80.9
+2020-08-28 11:00:00,18.95,137.0,0.0,137.0,3.52,78.25
+2020-08-28 12:00:00,19.19,223.0,0.0,223.0,3.72,75.65
+2020-08-28 13:00:00,19.17,301.0,30.42,281.0,3.66,75.65
+2020-08-28 14:00:00,19.49,316.0,102.51,259.0,4.0,73.15
+2020-08-28 15:00:00,19.31,120.0,0.0,120.0,3.38,75.65
+2020-08-28 16:00:00,19.15,111.0,29.14,103.0,3.03,73.05
+2020-08-28 17:00:00,18.76,47.0,61.64,40.0,2.55,75.55
+2020-08-28 18:00:00,18.05,0.0,-0.0,0.0,2.14,75.45
+2020-08-28 19:00:00,17.1,0.0,-0.0,0.0,2.34,75.4
+2020-08-28 20:00:00,16.76,0.0,-0.0,0.0,2.34,78.0
+2020-08-28 21:00:00,16.44,0.0,-0.0,0.0,2.34,78.0
+2020-08-28 22:00:00,15.98,0.0,-0.0,0.0,2.41,80.75
+2020-08-28 23:00:00,15.92,0.0,-0.0,0.0,2.41,83.55
+2020-08-29 00:00:00,15.92,0.0,-0.0,0.0,2.62,83.55
+2020-08-29 01:00:00,15.99,0.0,-0.0,0.0,2.83,80.75
+2020-08-29 02:00:00,15.79,0.0,-0.0,0.0,2.9,83.55
+2020-08-29 03:00:00,15.72,0.0,-0.0,0.0,3.03,83.55
+2020-08-29 04:00:00,15.85,0.0,-0.0,0.0,3.17,86.5
+2020-08-29 05:00:00,15.68,49.0,29.08,45.0,3.17,86.5
+2020-08-29 06:00:00,16.09,49.0,0.0,49.0,3.66,86.55
+2020-08-29 07:00:00,16.33,120.0,0.0,120.0,4.14,89.65
+2020-08-29 08:00:00,16.53,157.0,0.0,157.0,3.86,86.6
+2020-08-29 09:00:00,16.64,175.0,0.0,175.0,4.69,86.6
+2020-08-29 10:00:00,17.12,216.0,0.0,216.0,4.55,83.7
+2020-08-29 11:00:00,17.66,337.0,26.91,317.0,4.62,83.7
+2020-08-29 12:00:00,18.4,202.0,0.0,202.0,5.38,80.9
+2020-08-29 13:00:00,19.12,469.0,255.83,302.0,5.86,75.65
+2020-08-29 14:00:00,18.8,148.0,0.0,148.0,5.52,78.25
+2020-08-29 15:00:00,18.72,135.0,2.38,134.0,5.45,78.25
+2020-08-29 16:00:00,18.37,79.0,3.72,78.0,4.76,80.9
+2020-08-29 17:00:00,17.98,39.0,27.8,36.0,3.86,80.9
+2020-08-29 18:00:00,17.47,0.0,-0.0,0.0,3.52,78.1
+2020-08-29 19:00:00,16.65,0.0,-0.0,0.0,2.48,80.8
+2020-08-29 20:00:00,16.39,0.0,-0.0,0.0,2.28,83.6
+2020-08-29 21:00:00,15.91,0.0,-0.0,0.0,2.07,83.55
+2020-08-29 22:00:00,15.3,0.0,-0.0,0.0,1.93,86.5
+2020-08-29 23:00:00,14.92,0.0,-0.0,0.0,1.72,89.5
+2020-08-30 00:00:00,14.64,0.0,-0.0,0.0,1.52,89.5
+2020-08-30 01:00:00,14.06,0.0,-0.0,0.0,1.52,92.7
+2020-08-30 02:00:00,13.88,0.0,-0.0,0.0,1.38,95.95
+2020-08-30 03:00:00,13.65,0.0,-0.0,0.0,1.24,95.95
+2020-08-30 04:00:00,13.05,0.0,-0.0,0.0,1.24,95.95
+2020-08-30 05:00:00,13.05,59.0,74.83,49.0,1.03,95.95
+2020-08-30 06:00:00,14.28,148.0,78.27,125.0,1.24,96.0
+2020-08-30 07:00:00,15.0,342.0,375.47,176.0,1.59,86.5
+2020-08-30 08:00:00,16.02,457.0,399.46,230.0,1.45,77.95
+2020-08-30 09:00:00,17.06,577.0,506.23,241.0,1.59,70.3
+2020-08-30 10:00:00,18.11,668.0,616.34,223.0,1.45,65.55
+2020-08-30 11:00:00,18.92,699.0,658.91,212.0,1.45,59.05
+2020-08-30 12:00:00,19.47,675.0,663.99,201.0,1.45,55.05
+2020-08-30 13:00:00,19.81,640.0,782.38,133.0,1.52,53.25
+2020-08-30 14:00:00,20.07,517.0,710.55,129.0,1.59,49.7
+2020-08-30 15:00:00,19.88,364.0,588.08,120.0,1.66,51.4
+2020-08-30 16:00:00,19.53,208.0,462.95,86.0,1.72,51.4
+2020-08-30 17:00:00,18.57,57.0,176.09,39.0,1.59,59.05
+2020-08-30 18:00:00,16.91,0.0,-0.0,0.0,1.93,63.05
+2020-08-30 19:00:00,15.55,0.0,-0.0,0.0,2.21,65.15
+2020-08-30 20:00:00,14.41,0.0,-0.0,0.0,2.34,72.3
+2020-08-30 21:00:00,13.45,0.0,-0.0,0.0,2.28,72.2
+2020-08-30 22:00:00,12.51,0.0,-0.0,0.0,2.21,77.45
+2020-08-30 23:00:00,11.8,0.0,-0.0,0.0,2.21,83.1
+2020-08-31 00:00:00,11.34,0.0,-0.0,0.0,2.28,83.05
+2020-08-31 01:00:00,10.92,0.0,-0.0,0.0,2.34,80.1
+2020-08-31 02:00:00,10.61,0.0,-0.0,0.0,2.34,83.0
+2020-08-31 03:00:00,10.39,0.0,-0.0,0.0,2.41,83.0
+2020-08-31 04:00:00,10.24,0.0,-0.0,0.0,2.41,82.95
+2020-08-31 05:00:00,10.44,84.0,308.4,44.0,2.48,83.0
+2020-08-31 06:00:00,12.38,247.0,572.31,81.0,2.28,80.2
+2020-08-31 07:00:00,14.96,405.0,677.55,108.0,2.55,72.45
+2020-08-31 08:00:00,16.76,548.0,752.92,123.0,2.69,67.75
+2020-08-31 09:00:00,18.22,645.0,745.64,153.0,2.69,63.3
+2020-08-31 10:00:00,19.46,725.0,812.05,142.0,2.97,59.15
+2020-08-31 11:00:00,20.35,750.0,831.49,139.0,3.1,55.3
+2020-08-31 12:00:00,21.07,712.0,796.52,147.0,3.31,49.95
+2020-08-31 13:00:00,21.6,656.0,837.98,117.0,3.38,48.3
+2020-08-31 14:00:00,21.84,524.0,744.96,121.0,3.31,46.6
+2020-08-31 15:00:00,21.79,370.0,632.39,111.0,3.03,46.6
+2020-08-31 16:00:00,19.11,210.0,500.1,81.0,2.81,51.13
+2020-08-31 17:00:00,18.55,63.0,321.36,32.0,2.71,53.15
+2020-08-31 18:00:00,18.0,0.0,-0.0,0.0,2.61,55.17
+2020-08-31 19:00:00,17.45,0.0,-0.0,0.0,2.51,57.19
+2020-08-31 20:00:00,16.89,0.0,-0.0,0.0,2.42,59.21
+2020-08-31 21:00:00,16.34,0.0,-0.0,0.0,2.32,61.22
+2020-08-31 22:00:00,15.78,0.0,-0.0,0.0,2.22,63.24
+2020-08-31 23:00:00,15.23,0.0,-0.0,0.0,2.12,65.26
+2020-09-01 00:00:00,14.67,0.0,-0.0,0.0,2.02,67.28
+2020-09-01 01:00:00,14.12,0.0,-0.0,0.0,1.93,69.3
+2020-09-01 02:00:00,13.57,0.0,-0.0,0.0,1.83,71.32
+2020-09-01 03:00:00,13.01,0.0,-0.0,0.0,1.73,73.34
+2020-09-01 04:00:00,12.46,0.0,-0.0,0.0,1.63,75.36
+2020-09-01 05:00:00,11.9,35.0,7.71,34.0,1.53,77.38
+2020-09-01 06:00:00,11.35,117.0,27.58,109.0,1.44,79.39
+2020-09-01 07:00:00,10.79,271.0,166.54,198.0,1.34,81.41
+2020-09-01 08:00:00,13.74,192.0,3.54,190.0,2.0,74.85
+2020-09-01 09:00:00,14.47,231.0,4.55,228.0,2.14,74.95
+2020-09-01 10:00:00,14.99,118.0,0.0,118.0,2.48,69.9
+2020-09-01 11:00:00,15.32,137.0,0.0,137.0,2.55,72.45
+2020-09-01 12:00:00,15.57,129.0,0.0,129.0,2.9,70.0
+2020-09-01 13:00:00,15.62,89.0,0.0,89.0,2.83,72.55
+2020-09-01 14:00:00,15.26,61.0,0.0,61.0,2.48,77.8
+2020-09-01 15:00:00,14.88,141.0,7.32,138.0,2.21,83.45
+2020-09-01 16:00:00,14.33,107.0,34.89,98.0,2.34,86.4
+2020-09-01 17:00:00,14.0,26.0,10.37,25.0,2.21,86.4
+2020-09-01 18:00:00,13.75,0.0,-0.0,0.0,2.0,89.45
+2020-09-01 19:00:00,14.09,0.0,-0.0,0.0,2.48,83.4
+2020-09-01 20:00:00,13.79,0.0,-0.0,0.0,2.34,86.35
+2020-09-01 21:00:00,13.51,0.0,-0.0,0.0,2.21,89.45
+2020-09-01 22:00:00,13.4,0.0,-0.0,0.0,2.14,92.65
+2020-09-01 23:00:00,13.27,0.0,-0.0,0.0,2.28,92.65
+2020-09-02 00:00:00,13.24,0.0,-0.0,0.0,2.55,92.65
+2020-09-02 01:00:00,12.99,0.0,-0.0,0.0,2.76,92.65
+2020-09-02 02:00:00,12.98,0.0,-0.0,0.0,2.83,92.65
+2020-09-02 03:00:00,12.94,0.0,-0.0,0.0,2.97,95.95
+2020-09-02 04:00:00,12.9,0.0,-0.0,0.0,3.17,95.95
+2020-09-02 05:00:00,12.9,7.0,0.0,7.0,3.31,95.95
+2020-09-02 06:00:00,12.93,40.0,0.0,40.0,3.24,99.4
+2020-09-02 07:00:00,13.07,58.0,0.0,58.0,3.24,92.65
+2020-09-02 08:00:00,13.43,95.0,0.0,95.0,3.38,92.65
+2020-09-02 09:00:00,14.15,92.0,0.0,92.0,3.31,89.5
+2020-09-02 10:00:00,14.49,119.0,0.0,119.0,3.24,92.7
+2020-09-02 11:00:00,15.22,151.0,0.0,151.0,3.24,86.5
+2020-09-02 12:00:00,16.31,160.0,0.0,160.0,2.9,83.6
+2020-09-02 13:00:00,17.49,142.0,0.0,142.0,2.34,80.85
+2020-09-02 14:00:00,18.16,118.0,0.0,118.0,2.0,78.25
+2020-09-02 15:00:00,18.98,107.0,0.0,107.0,2.14,75.65
+2020-09-02 16:00:00,18.82,99.0,27.74,92.0,2.28,81.05
+2020-09-02 17:00:00,18.31,32.0,33.09,29.0,2.07,83.8
+2020-09-02 18:00:00,17.61,0.0,-0.0,0.0,1.66,86.7
+2020-09-02 19:00:00,17.83,0.0,-0.0,0.0,1.38,89.75
+2020-09-02 20:00:00,17.19,0.0,-0.0,0.0,1.38,92.85
+2020-09-02 21:00:00,16.82,0.0,-0.0,0.0,1.66,92.8
+2020-09-02 22:00:00,16.8,0.0,-0.0,0.0,1.79,96.05
+2020-09-02 23:00:00,16.84,0.0,-0.0,0.0,1.66,96.05
+2020-09-03 00:00:00,16.88,0.0,-0.0,0.0,1.52,96.05
+2020-09-03 01:00:00,16.79,0.0,-0.0,0.0,1.59,96.05
+2020-09-03 02:00:00,16.57,0.0,-0.0,0.0,1.66,92.8
+2020-09-03 03:00:00,16.48,0.0,-0.0,0.0,1.86,96.05
+2020-09-03 04:00:00,16.29,0.0,-0.0,0.0,1.93,92.8
+2020-09-03 05:00:00,16.07,64.0,156.01,45.0,1.79,92.8
+2020-09-03 06:00:00,16.79,70.0,0.0,70.0,1.66,92.8
+2020-09-03 07:00:00,17.96,250.0,130.02,194.0,1.93,86.7
+2020-09-03 08:00:00,19.6,475.0,526.26,182.0,2.55,75.7
+2020-09-03 09:00:00,20.22,451.0,227.03,303.0,2.55,73.2
+2020-09-03 10:00:00,21.22,460.0,167.69,341.0,2.76,68.5
+2020-09-03 11:00:00,21.8,128.0,0.0,128.0,2.69,66.25
+2020-09-03 12:00:00,22.28,113.0,0.0,113.0,2.69,64.1
+2020-09-03 13:00:00,22.73,287.0,30.0,268.0,2.83,62.05
+2020-09-03 14:00:00,22.69,255.0,47.12,230.0,2.83,57.9
+2020-09-03 15:00:00,21.81,136.0,7.52,133.0,2.07,66.25
+2020-09-03 16:00:00,20.86,148.0,186.52,102.0,2.14,73.3
+2020-09-03 17:00:00,20.16,36.0,70.75,30.0,2.07,75.75
+2020-09-03 18:00:00,19.48,0.0,-0.0,0.0,1.79,78.3
+2020-09-03 19:00:00,19.24,0.0,-0.0,0.0,1.38,81.05
+2020-09-03 20:00:00,18.64,0.0,-0.0,0.0,1.59,78.3
+2020-09-03 21:00:00,18.3,0.0,-0.0,0.0,1.93,78.25
+2020-09-03 22:00:00,17.67,0.0,-0.0,0.0,2.0,78.15
+2020-09-03 23:00:00,16.67,0.0,-0.0,0.0,1.86,83.65
+2020-09-04 00:00:00,16.39,0.0,-0.0,0.0,1.52,86.55
+2020-09-04 01:00:00,16.46,0.0,-0.0,0.0,1.31,86.55
+2020-09-04 02:00:00,17.33,0.0,-0.0,0.0,1.03,80.85
+2020-09-04 03:00:00,17.62,0.0,-0.0,0.0,0.76,80.9
+2020-09-04 04:00:00,17.08,0.0,-0.0,0.0,0.83,83.7
+2020-09-04 05:00:00,15.12,56.0,110.35,43.0,1.24,89.55
+2020-09-04 06:00:00,16.35,169.0,183.15,118.0,0.83,89.65
+2020-09-04 07:00:00,18.7,320.0,349.07,171.0,1.66,83.85
+2020-09-04 08:00:00,19.73,498.0,622.24,154.0,1.86,81.1
+2020-09-04 09:00:00,21.23,600.0,656.0,175.0,2.07,73.35
+2020-09-04 10:00:00,22.06,639.0,591.12,222.0,2.62,66.35
+2020-09-04 11:00:00,22.67,259.0,4.16,256.0,2.83,62.05
+2020-09-04 12:00:00,23.14,252.0,4.31,249.0,2.62,60.05
+2020-09-04 13:00:00,23.62,486.0,342.13,271.0,2.41,56.15
+2020-09-04 14:00:00,23.48,455.0,540.61,171.0,2.48,56.0
+2020-09-04 15:00:00,23.11,199.0,68.68,172.0,2.55,56.0
+2020-09-04 16:00:00,22.49,121.0,87.18,100.0,2.41,61.95
+2020-09-04 17:00:00,21.53,21.0,12.67,20.0,1.93,66.15
+2020-09-04 18:00:00,20.45,0.0,-0.0,0.0,1.66,70.7
+2020-09-04 19:00:00,19.62,0.0,-0.0,0.0,1.66,70.65
+2020-09-04 20:00:00,18.51,0.0,-0.0,0.0,1.59,72.95
+2020-09-04 21:00:00,17.67,0.0,-0.0,0.0,1.66,72.9
+2020-09-04 22:00:00,17.27,0.0,-0.0,0.0,1.52,75.4
+2020-09-04 23:00:00,18.25,0.0,-0.0,0.0,1.1,68.05
+2020-09-05 00:00:00,18.8,0.0,-0.0,0.0,0.41,65.75
+2020-09-05 01:00:00,18.39,0.0,-0.0,0.0,0.34,68.05
+2020-09-05 02:00:00,17.75,0.0,-0.0,0.0,0.83,70.35
+2020-09-05 03:00:00,17.11,0.0,-0.0,0.0,0.97,72.8
+2020-09-05 04:00:00,16.64,0.0,-0.0,0.0,0.97,75.3
+2020-09-05 05:00:00,16.35,49.0,70.3,41.0,0.76,77.95
+2020-09-05 06:00:00,16.65,226.0,539.06,78.0,0.14,78.0
+2020-09-05 07:00:00,17.68,359.0,529.61,135.0,0.21,80.9
+2020-09-05 08:00:00,19.36,478.0,537.45,183.0,0.62,75.65
+2020-09-05 09:00:00,20.82,610.0,689.67,166.0,1.17,70.8
+2020-09-05 10:00:00,22.02,717.0,852.86,119.0,1.72,64.0
+2020-09-05 11:00:00,23.05,721.0,815.74,136.0,1.93,55.9
+2020-09-05 12:00:00,23.4,619.0,553.14,237.0,1.93,50.45
+2020-09-05 13:00:00,23.6,457.0,267.9,290.0,1.93,47.15
+2020-09-05 14:00:00,23.53,425.0,428.84,202.0,2.0,48.7
+2020-09-05 15:00:00,23.2,283.0,307.04,164.0,2.14,48.7
+2020-09-05 16:00:00,22.76,158.0,267.98,95.0,2.07,50.3
+2020-09-05 17:00:00,21.7,33.0,95.95,26.0,1.72,53.75
+2020-09-05 18:00:00,20.11,0.0,-0.0,0.0,1.86,59.35
+2020-09-05 19:00:00,18.67,0.0,-0.0,0.0,1.72,65.75
+2020-09-05 20:00:00,17.16,0.0,-0.0,0.0,1.79,72.8
+2020-09-05 21:00:00,15.93,0.0,-0.0,0.0,2.0,77.85
+2020-09-05 22:00:00,15.26,0.0,-0.0,0.0,2.0,80.6
+2020-09-05 23:00:00,14.72,0.0,-0.0,0.0,1.93,83.45
+2020-09-06 00:00:00,14.38,0.0,-0.0,0.0,1.79,86.4
+2020-09-06 01:00:00,14.19,0.0,-0.0,0.0,1.59,86.4
+2020-09-06 02:00:00,13.61,0.0,-0.0,0.0,1.66,89.45
+2020-09-06 03:00:00,13.26,0.0,-0.0,0.0,1.59,92.65
+2020-09-06 04:00:00,13.07,0.0,-0.0,0.0,1.59,92.65
+2020-09-06 05:00:00,12.94,53.0,118.41,40.0,1.59,95.95
+2020-09-06 06:00:00,15.34,171.0,214.33,113.0,1.1,86.5
+2020-09-06 07:00:00,18.93,316.0,355.59,167.0,1.52,70.55
+2020-09-06 08:00:00,20.54,509.0,701.05,127.0,1.93,63.7
+2020-09-06 09:00:00,21.77,641.0,825.44,113.0,2.14,57.65
+2020-09-06 10:00:00,22.68,713.0,863.88,111.0,2.28,52.1
+2020-09-06 11:00:00,23.52,739.0,891.13,104.0,2.0,50.45
+2020-09-06 12:00:00,23.81,675.0,783.06,138.0,1.45,47.15
+2020-09-06 13:00:00,24.06,504.0,412.45,249.0,1.24,47.15
+2020-09-06 14:00:00,24.11,401.0,367.26,212.0,1.24,45.6
+2020-09-06 15:00:00,23.97,344.0,649.32,96.0,1.38,47.15
+2020-09-06 16:00:00,23.47,165.0,357.68,83.0,1.52,50.45
+2020-09-06 17:00:00,22.23,9.0,0.0,9.0,1.86,53.85
+2020-09-06 18:00:00,20.93,0.0,-0.0,0.0,2.07,59.5
+2020-09-06 19:00:00,20.41,0.0,-0.0,0.0,2.21,59.35
+2020-09-06 20:00:00,19.21,0.0,-0.0,0.0,2.21,65.75
+2020-09-06 21:00:00,18.43,0.0,-0.0,0.0,2.14,70.45
+2020-09-06 22:00:00,18.06,0.0,-0.0,0.0,2.07,70.45
+2020-09-06 23:00:00,17.56,0.0,-0.0,0.0,2.14,70.35
+2020-09-07 00:00:00,17.31,0.0,-0.0,0.0,2.21,70.3
+2020-09-07 01:00:00,16.93,0.0,-0.0,0.0,2.28,72.7
+2020-09-07 02:00:00,16.61,0.0,-0.0,0.0,2.21,70.2
+2020-09-07 03:00:00,16.06,0.0,-0.0,0.0,2.21,72.65
+2020-09-07 04:00:00,15.83,0.0,-0.0,0.0,2.07,75.15
+2020-09-07 05:00:00,15.21,6.0,0.0,6.0,1.72,80.6
+2020-09-07 06:00:00,16.13,19.0,0.0,19.0,1.31,80.75
+2020-09-07 07:00:00,16.91,318.0,387.9,157.0,1.03,83.65
+2020-09-07 08:00:00,17.73,166.0,1.85,165.0,1.24,80.9
+2020-09-07 09:00:00,17.65,330.0,62.94,290.0,1.24,86.7
+2020-09-07 10:00:00,18.18,112.0,0.0,112.0,1.31,86.75
+2020-09-07 11:00:00,18.62,88.0,0.0,88.0,1.03,83.85
+2020-09-07 12:00:00,19.67,294.0,20.56,280.0,1.31,81.1
+2020-09-07 13:00:00,19.49,104.0,0.0,104.0,1.31,83.85
+2020-09-07 14:00:00,20.12,428.0,496.88,175.0,1.1,78.45
+2020-09-07 15:00:00,20.82,278.0,342.85,149.0,1.59,68.4
+2020-09-07 16:00:00,20.93,169.0,438.73,71.0,1.52,63.8
+2020-09-07 17:00:00,20.37,27.0,98.45,21.0,0.69,70.7
+2020-09-07 18:00:00,19.14,0.0,-0.0,0.0,0.9,73.05
+2020-09-07 19:00:00,17.13,0.0,-0.0,0.0,1.52,80.85
+2020-09-07 20:00:00,16.43,0.0,-0.0,0.0,1.52,86.55
+2020-09-07 21:00:00,16.59,0.0,-0.0,0.0,1.79,78.0
+2020-09-07 22:00:00,16.81,0.0,-0.0,0.0,2.14,75.3
+2020-09-07 23:00:00,16.68,0.0,-0.0,0.0,2.41,72.7
+2020-09-08 00:00:00,16.36,0.0,-0.0,0.0,2.48,75.25
+2020-09-08 01:00:00,15.89,0.0,-0.0,0.0,2.21,77.85
+2020-09-08 02:00:00,15.13,0.0,-0.0,0.0,1.93,80.6
+2020-09-08 03:00:00,14.53,0.0,-0.0,0.0,1.86,80.55
+2020-09-08 04:00:00,13.54,0.0,-0.0,0.0,2.0,86.35
+2020-09-08 05:00:00,12.87,33.0,19.67,31.0,1.86,89.4
+2020-09-08 06:00:00,13.78,154.0,156.09,113.0,1.59,86.35
+2020-09-08 07:00:00,15.14,374.0,664.13,101.0,1.79,75.1
+2020-09-08 08:00:00,16.02,499.0,672.52,138.0,1.72,65.25
+2020-09-08 09:00:00,16.65,493.0,340.58,278.0,1.66,63.05
+2020-09-08 10:00:00,18.17,650.0,662.73,194.0,2.34,54.95
+2020-09-08 11:00:00,19.1,685.0,732.26,170.0,2.48,51.25
+2020-09-08 12:00:00,19.74,688.0,837.34,122.0,2.28,47.8
+2020-09-08 13:00:00,20.21,610.0,817.62,113.0,1.93,44.6
+2020-09-08 14:00:00,20.87,476.0,710.76,118.0,1.59,43.1
+2020-09-08 15:00:00,20.96,290.0,399.43,142.0,1.24,43.1
+2020-09-08 16:00:00,20.74,167.0,441.49,71.0,1.1,43.1
+2020-09-08 17:00:00,19.49,29.0,182.2,19.0,1.59,51.25
+2020-09-08 18:00:00,17.49,0.0,-0.0,0.0,1.72,56.75
+2020-09-08 19:00:00,15.52,0.0,-0.0,0.0,1.86,62.85
+2020-09-08 20:00:00,14.38,0.0,-0.0,0.0,1.72,69.75
+2020-09-08 21:00:00,13.7,0.0,-0.0,0.0,2.0,69.65
+2020-09-08 22:00:00,13.2,0.0,-0.0,0.0,2.14,72.1
+2020-09-08 23:00:00,12.84,0.0,-0.0,0.0,2.07,77.45
+2020-09-09 00:00:00,12.45,0.0,-0.0,0.0,1.93,80.2
+2020-09-09 01:00:00,12.01,0.0,-0.0,0.0,1.86,83.15
+2020-09-09 02:00:00,11.8,0.0,-0.0,0.0,1.79,86.15
+2020-09-09 03:00:00,11.29,0.0,-0.0,0.0,1.86,89.3
+2020-09-09 04:00:00,10.91,0.0,-0.0,0.0,1.86,89.25
+2020-09-09 05:00:00,10.87,33.0,30.73,30.0,1.79,89.25
+2020-09-09 06:00:00,12.71,114.0,46.39,102.0,1.31,86.25
+2020-09-09 07:00:00,16.22,171.0,24.57,161.0,1.1,72.65
+2020-09-09 08:00:00,18.4,326.0,137.04,253.0,0.97,63.4
+2020-09-09 09:00:00,20.05,367.0,103.67,302.0,1.03,53.35
+2020-09-09 10:00:00,21.15,657.0,708.02,173.0,0.97,48.2
+2020-09-09 11:00:00,22.18,625.0,545.39,244.0,1.17,45.1
+2020-09-09 12:00:00,22.99,561.0,432.22,271.0,1.59,43.65
+2020-09-09 13:00:00,23.43,412.0,205.78,288.0,1.66,40.75
+2020-09-09 14:00:00,23.43,491.0,792.94,96.0,1.72,40.75
+2020-09-09 15:00:00,23.07,324.0,625.09,96.0,1.86,42.1
+2020-09-09 16:00:00,22.32,173.0,524.87,62.0,1.72,46.75
+2020-09-09 17:00:00,20.99,20.0,81.98,16.0,1.66,53.5
+2020-09-09 18:00:00,18.95,0.0,-0.0,0.0,1.38,63.5
+2020-09-09 19:00:00,18.77,0.0,-0.0,0.0,1.1,57.1
+2020-09-09 20:00:00,19.65,0.0,-0.0,0.0,0.34,51.4
+2020-09-09 21:00:00,18.61,0.0,-0.0,0.0,1.1,53.15
+2020-09-09 22:00:00,16.24,0.0,-0.0,0.0,1.45,65.25
+2020-09-09 23:00:00,14.73,0.0,-0.0,0.0,1.72,72.4
+2020-09-10 00:00:00,13.86,0.0,-0.0,0.0,1.79,77.6
+2020-09-10 01:00:00,13.1,0.0,-0.0,0.0,1.86,80.35
+2020-09-10 02:00:00,12.41,0.0,-0.0,0.0,1.86,86.2
+2020-09-10 03:00:00,11.85,0.0,-0.0,0.0,1.86,89.3
+2020-09-10 04:00:00,11.46,0.0,-0.0,0.0,1.86,89.3
+2020-09-10 05:00:00,11.13,53.0,224.5,32.0,1.86,89.3
+2020-09-10 06:00:00,13.24,203.0,498.78,76.0,1.38,86.3
+2020-09-10 07:00:00,17.87,367.0,667.51,98.0,1.17,67.95
+2020-09-10 08:00:00,21.04,517.0,783.3,103.0,0.97,57.45
+2020-09-10 09:00:00,22.82,610.0,772.44,129.0,1.31,46.85
+2020-09-10 10:00:00,23.8,504.0,275.37,317.0,1.59,43.9
+2020-09-10 11:00:00,24.54,679.0,750.92,158.0,1.79,42.5
+2020-09-10 12:00:00,25.07,510.0,313.86,301.0,2.07,39.7
+2020-09-10 13:00:00,25.44,563.0,684.79,154.0,2.28,35.8
+2020-09-10 14:00:00,25.45,442.0,602.97,145.0,2.48,34.5
+2020-09-10 15:00:00,25.2,141.0,16.72,135.0,2.34,34.5
+2020-09-10 16:00:00,24.22,47.0,0.0,47.0,1.38,42.5
+2020-09-10 17:00:00,22.98,10.0,0.0,10.0,0.76,52.1
+2020-09-10 18:00:00,22.71,0.0,-0.0,0.0,0.69,43.65
+2020-09-10 19:00:00,19.68,0.0,-0.0,0.0,1.52,63.6
+2020-09-10 20:00:00,19.04,0.0,-0.0,0.0,1.93,63.5
+2020-09-10 21:00:00,18.0,0.0,-0.0,0.0,1.52,67.95
+2020-09-10 22:00:00,17.36,0.0,-0.0,0.0,1.45,72.8
+2020-09-10 23:00:00,17.16,0.0,-0.0,0.0,1.79,70.3
+2020-09-11 00:00:00,17.35,0.0,-0.0,0.0,2.0,67.85
+2020-09-11 01:00:00,16.95,0.0,-0.0,0.0,1.72,70.2
+2020-09-11 02:00:00,16.57,0.0,-0.0,0.0,1.38,72.7
+2020-09-11 03:00:00,16.19,0.0,-0.0,0.0,1.31,75.25
+2020-09-11 04:00:00,15.76,0.0,-0.0,0.0,1.31,77.85
+2020-09-11 05:00:00,15.68,15.0,0.0,15.0,1.31,80.65
+2020-09-11 06:00:00,16.38,40.0,0.0,40.0,1.24,80.75
+2020-09-11 07:00:00,18.04,272.0,245.68,174.0,0.83,68.05
+2020-09-11 08:00:00,19.21,496.0,726.62,115.0,1.31,63.5
+2020-09-11 09:00:00,21.48,585.0,706.72,148.0,2.62,55.55
+2020-09-11 10:00:00,23.04,546.0,395.84,279.0,3.66,48.55
+2020-09-11 11:00:00,23.9,649.0,674.9,184.0,3.86,43.9
+2020-09-11 12:00:00,24.76,551.0,440.37,260.0,4.0,38.3
+2020-09-11 13:00:00,25.28,413.0,231.46,276.0,4.07,34.5
+2020-09-11 14:00:00,25.2,372.0,349.13,202.0,4.0,33.3
+2020-09-11 15:00:00,24.94,266.0,368.21,136.0,3.66,34.4
+2020-09-11 16:00:00,24.25,131.0,265.75,78.0,2.69,36.8
+2020-09-11 17:00:00,22.94,9.0,0.0,9.0,2.34,42.1
+2020-09-11 18:00:00,21.52,0.0,-0.0,0.0,2.28,46.5
+2020-09-11 19:00:00,20.81,0.0,-0.0,0.0,2.41,44.7
+2020-09-11 20:00:00,19.79,0.0,-0.0,0.0,2.55,47.8
+2020-09-11 21:00:00,19.13,0.0,-0.0,0.0,2.69,51.25
+2020-09-11 22:00:00,18.6,0.0,-0.0,0.0,2.69,53.15
+2020-09-11 23:00:00,18.05,0.0,-0.0,0.0,2.62,54.95
+2020-09-12 00:00:00,17.31,0.0,-0.0,0.0,2.41,60.95
+2020-09-12 01:00:00,16.51,0.0,-0.0,0.0,2.41,63.05
+2020-09-12 02:00:00,15.75,0.0,-0.0,0.0,2.34,67.55
+2020-09-12 03:00:00,15.02,0.0,-0.0,0.0,2.28,69.9
+2020-09-12 04:00:00,14.37,0.0,-0.0,0.0,2.21,74.95
+2020-09-12 05:00:00,13.89,47.0,222.7,28.0,2.14,77.6
+2020-09-12 06:00:00,15.23,204.0,547.71,69.0,1.79,77.8
+2020-09-12 07:00:00,20.0,362.0,681.39,93.0,1.66,61.4
+2020-09-12 08:00:00,22.75,512.0,795.96,98.0,2.28,48.55
+2020-09-12 09:00:00,24.7,625.0,851.85,102.0,2.76,42.65
+2020-09-12 10:00:00,26.05,683.0,849.38,114.0,3.1,38.55
+2020-09-12 11:00:00,27.03,701.0,856.57,115.0,3.31,33.7
+2020-09-12 12:00:00,27.71,654.0,800.71,129.0,3.38,29.4
+2020-09-12 13:00:00,28.03,583.0,799.71,114.0,3.17,29.4
+2020-09-12 14:00:00,28.04,461.0,739.75,105.0,3.03,29.4
+2020-09-12 15:00:00,27.73,311.0,639.47,89.0,2.83,30.5
+2020-09-12 16:00:00,26.65,142.0,387.87,67.0,1.93,37.5
+2020-09-12 17:00:00,24.73,7.0,0.0,7.0,1.72,44.15
+2020-09-12 18:00:00,23.56,0.0,-0.0,0.0,1.1,48.7
+2020-09-12 19:00:00,22.03,0.0,-0.0,0.0,1.31,51.9
+2020-09-12 20:00:00,20.65,0.0,-0.0,0.0,3.38,55.45
+2020-09-12 21:00:00,18.71,0.0,-0.0,0.0,3.38,65.75
+2020-09-12 22:00:00,17.21,0.0,-0.0,0.0,2.41,78.1
+2020-09-12 23:00:00,16.28,0.0,-0.0,0.0,2.0,83.6
+2020-09-13 00:00:00,15.55,0.0,-0.0,0.0,1.79,86.5
+2020-09-13 01:00:00,14.54,0.0,-0.0,0.0,1.79,86.45
+2020-09-13 02:00:00,14.21,0.0,-0.0,0.0,1.66,89.5
+2020-09-13 03:00:00,13.83,0.0,-0.0,0.0,1.59,89.45
+2020-09-13 04:00:00,13.57,0.0,-0.0,0.0,1.45,89.45
+2020-09-13 05:00:00,13.51,6.0,0.0,6.0,1.38,89.45
+2020-09-13 06:00:00,14.24,60.0,0.0,60.0,1.72,86.4
+2020-09-13 07:00:00,14.67,166.0,30.72,154.0,2.55,83.45
+2020-09-13 08:00:00,15.56,184.0,5.82,181.0,2.14,77.85
+2020-09-13 09:00:00,16.2,349.0,100.08,288.0,2.0,77.95
+2020-09-13 10:00:00,17.08,175.0,0.0,175.0,2.0,75.4
+2020-09-13 11:00:00,17.63,128.0,0.0,128.0,2.0,75.45
+2020-09-13 12:00:00,18.25,91.0,0.0,91.0,2.0,75.55
+2020-09-13 13:00:00,18.36,101.0,0.0,101.0,1.86,75.55
+2020-09-13 14:00:00,18.14,195.0,18.93,186.0,1.93,75.55
+2020-09-13 15:00:00,17.78,109.0,2.93,108.0,2.07,78.15
+2020-09-13 16:00:00,17.25,39.0,0.0,39.0,2.0,80.85
+2020-09-13 17:00:00,16.64,4.0,0.0,4.0,1.86,83.65
+2020-09-13 18:00:00,16.0,0.0,-0.0,0.0,1.59,86.5
+2020-09-13 19:00:00,14.91,0.0,-0.0,0.0,1.72,92.7
+2020-09-13 20:00:00,14.55,0.0,-0.0,0.0,1.38,92.7
+2020-09-13 21:00:00,14.37,0.0,-0.0,0.0,1.24,96.0
+2020-09-13 22:00:00,14.12,0.0,-0.0,0.0,1.38,96.0
+2020-09-13 23:00:00,13.92,0.0,-0.0,0.0,1.31,95.95
+2020-09-14 00:00:00,13.78,0.0,-0.0,0.0,1.17,95.95
+2020-09-14 01:00:00,13.99,0.0,-0.0,0.0,1.17,92.7
+2020-09-14 02:00:00,13.73,0.0,-0.0,0.0,1.17,95.95
+2020-09-14 03:00:00,13.59,0.0,-0.0,0.0,1.24,95.95
+2020-09-14 04:00:00,13.55,0.0,-0.0,0.0,1.38,92.65
+2020-09-14 05:00:00,13.39,42.0,220.69,25.0,1.45,95.95
+2020-09-14 06:00:00,13.51,37.0,0.0,37.0,1.79,92.65
+2020-09-14 07:00:00,13.42,79.0,0.0,79.0,1.31,99.4
+2020-09-14 08:00:00,13.43,113.0,0.0,113.0,1.45,95.95
+2020-09-14 09:00:00,13.88,99.0,0.0,99.0,1.31,89.45
+2020-09-14 10:00:00,14.92,210.0,1.51,209.0,1.45,83.45
+2020-09-14 11:00:00,15.41,208.0,0.0,208.0,1.59,80.6
+2020-09-14 12:00:00,15.82,127.0,0.0,127.0,1.52,77.85
+2020-09-14 13:00:00,16.42,125.0,0.0,125.0,1.45,75.25
+2020-09-14 14:00:00,16.62,234.0,57.48,207.0,1.31,72.7
+2020-09-14 15:00:00,16.83,229.0,256.53,143.0,1.1,72.7
+2020-09-14 16:00:00,16.63,68.0,27.6,63.0,0.97,72.7
+2020-09-14 17:00:00,16.33,0.0,0.0,0.0,0.76,75.25
+2020-09-14 18:00:00,15.56,0.0,-0.0,0.0,0.83,80.65
+2020-09-14 19:00:00,15.15,0.0,-0.0,0.0,1.59,83.5
+2020-09-14 20:00:00,14.35,0.0,-0.0,0.0,1.72,86.4
+2020-09-14 21:00:00,13.85,0.0,-0.0,0.0,1.72,89.45
+2020-09-14 22:00:00,13.46,0.0,-0.0,0.0,1.72,92.65
+2020-09-14 23:00:00,13.46,0.0,-0.0,0.0,1.66,92.65
+2020-09-15 00:00:00,13.86,0.0,-0.0,0.0,1.52,92.65
+2020-09-15 01:00:00,14.08,0.0,-0.0,0.0,1.59,89.5
+2020-09-15 02:00:00,13.94,0.0,-0.0,0.0,1.72,92.65
+2020-09-15 03:00:00,13.92,0.0,-0.0,0.0,1.66,92.65
+2020-09-15 04:00:00,13.7,0.0,-0.0,0.0,1.79,92.65
+2020-09-15 05:00:00,13.13,22.0,13.72,21.0,1.93,92.65
+2020-09-15 06:00:00,13.81,58.0,0.0,58.0,1.79,92.65
+2020-09-15 07:00:00,15.45,212.0,104.64,172.0,2.48,86.5
+2020-09-15 08:00:00,16.5,414.0,425.84,198.0,3.1,72.65
+2020-09-15 09:00:00,17.43,538.0,562.83,200.0,3.38,58.8
+2020-09-15 10:00:00,18.38,373.0,86.92,316.0,3.72,49.3
+2020-09-15 11:00:00,19.18,242.0,4.48,239.0,4.14,44.3
+2020-09-15 12:00:00,19.66,588.0,601.62,203.0,4.07,41.3
+2020-09-15 13:00:00,19.95,207.0,5.26,204.0,4.0,39.8
+2020-09-15 14:00:00,19.69,255.0,86.22,215.0,3.79,39.8
+2020-09-15 15:00:00,19.29,271.0,485.97,111.0,3.17,44.3
+2020-09-15 16:00:00,18.72,126.0,371.49,61.0,2.21,47.65
+2020-09-15 17:00:00,17.77,0.0,0.0,0.0,1.59,52.9
+2020-09-15 18:00:00,16.1,0.0,-0.0,0.0,1.38,62.95
+2020-09-15 19:00:00,14.53,0.0,-0.0,0.0,1.59,67.35
+2020-09-15 20:00:00,13.45,0.0,-0.0,0.0,1.79,72.1
+2020-09-15 21:00:00,12.6,0.0,-0.0,0.0,1.93,72.05
+2020-09-15 22:00:00,12.08,0.0,-0.0,0.0,1.93,74.6
+2020-09-15 23:00:00,11.94,0.0,-0.0,0.0,1.79,77.3
+2020-09-16 00:00:00,11.98,0.0,-0.0,0.0,1.59,77.35
+2020-09-16 01:00:00,11.73,0.0,-0.0,0.0,1.52,80.15
+2020-09-16 02:00:00,11.59,0.0,-0.0,0.0,1.38,83.1
+2020-09-16 03:00:00,11.32,0.0,-0.0,0.0,1.31,83.05
+2020-09-16 04:00:00,11.22,0.0,-0.0,0.0,1.24,83.05
+2020-09-16 05:00:00,10.64,31.0,116.48,23.0,1.38,86.05
+2020-09-16 06:00:00,12.06,179.0,469.73,71.0,0.83,83.15
+2020-09-16 07:00:00,14.68,321.0,542.32,116.0,0.69,75.0
+2020-09-16 08:00:00,16.59,453.0,608.52,147.0,1.03,65.35
+2020-09-16 09:00:00,18.22,569.0,713.12,144.0,1.45,59.05
+2020-09-16 10:00:00,19.65,586.0,565.29,218.0,1.86,53.25
+2020-09-16 11:00:00,20.83,580.0,502.88,246.0,2.28,46.35
+2020-09-16 12:00:00,21.5,622.0,762.67,138.0,2.14,43.25
+2020-09-16 13:00:00,21.86,545.0,742.47,126.0,2.0,41.85
+2020-09-16 14:00:00,22.02,418.0,646.13,122.0,1.79,40.35
+2020-09-16 15:00:00,21.95,271.0,532.17,99.0,1.72,40.35
+2020-09-16 16:00:00,21.36,108.0,242.91,67.0,1.45,43.25
+2020-09-16 17:00:00,19.77,0.0,0.0,0.0,1.93,49.55
+2020-09-16 18:00:00,17.89,0.0,-0.0,0.0,2.21,54.85
+2020-09-16 19:00:00,16.81,0.0,-0.0,0.0,2.21,56.6
+2020-09-16 20:00:00,15.68,0.0,-0.0,0.0,2.34,60.65
+2020-09-16 21:00:00,14.81,0.0,-0.0,0.0,2.41,64.95
+2020-09-16 22:00:00,14.27,0.0,-0.0,0.0,2.41,64.85
+2020-09-16 23:00:00,13.73,0.0,-0.0,0.0,2.41,67.15
+2020-09-17 00:00:00,13.29,0.0,-0.0,0.0,2.34,69.55
+2020-09-17 01:00:00,12.63,0.0,-0.0,0.0,2.28,74.7
+2020-09-17 02:00:00,12.08,0.0,-0.0,0.0,2.28,77.35
+2020-09-17 03:00:00,11.61,0.0,-0.0,0.0,2.28,80.15
+2020-09-17 04:00:00,11.37,0.0,-0.0,0.0,2.28,83.05
+2020-09-17 05:00:00,11.14,30.0,124.06,22.0,2.21,83.05
+2020-09-17 06:00:00,12.22,184.0,522.77,66.0,2.0,83.15
+2020-09-17 07:00:00,15.72,336.0,639.48,97.0,1.93,72.55
+2020-09-17 08:00:00,18.97,484.0,754.33,108.0,1.93,61.3
+2020-09-17 09:00:00,21.27,599.0,828.58,109.0,2.0,55.55
+2020-09-17 10:00:00,22.79,649.0,801.66,131.0,1.79,50.3
+2020-09-17 11:00:00,23.84,574.0,488.57,252.0,1.59,45.5
+2020-09-17 12:00:00,24.52,616.0,743.75,148.0,1.17,42.5
+2020-09-17 13:00:00,24.97,536.0,712.37,138.0,0.83,39.7
+2020-09-17 14:00:00,25.1,417.0,654.52,121.0,0.55,38.45
+2020-09-17 15:00:00,25.03,227.0,296.4,133.0,0.62,39.7
+2020-09-17 16:00:00,24.27,113.0,332.13,59.0,1.1,45.6
+2020-09-17 17:00:00,22.27,0.0,-0.0,0.0,2.0,52.0
+2020-09-17 18:00:00,20.11,0.0,-0.0,0.0,2.21,59.35
+2020-09-17 19:00:00,19.06,0.0,-0.0,0.0,2.34,57.1
+2020-09-17 20:00:00,17.99,0.0,-0.0,0.0,2.41,58.9
+2020-09-17 21:00:00,17.21,0.0,-0.0,0.0,2.55,60.95
+2020-09-17 22:00:00,16.68,0.0,-0.0,0.0,2.55,63.05
+2020-09-17 23:00:00,16.22,0.0,-0.0,0.0,2.55,67.65
+2020-09-18 00:00:00,15.74,0.0,-0.0,0.0,2.55,70.0
+2020-09-18 01:00:00,15.28,0.0,-0.0,0.0,2.48,72.45
+2020-09-18 02:00:00,14.88,0.0,-0.0,0.0,2.55,75.0
+2020-09-18 03:00:00,14.52,0.0,-0.0,0.0,2.48,75.0
+2020-09-18 04:00:00,14.08,0.0,-0.0,0.0,2.48,77.65
+2020-09-18 05:00:00,13.89,20.0,33.18,18.0,2.55,83.35
+2020-09-18 06:00:00,15.09,157.0,338.6,82.0,2.41,77.8
+2020-09-18 07:00:00,18.16,326.0,614.44,99.0,2.28,65.65
+2020-09-18 08:00:00,20.9,471.0,730.74,110.0,2.76,61.6
+2020-09-18 09:00:00,22.82,579.0,784.0,119.0,2.83,57.9
+2020-09-18 10:00:00,24.36,627.0,751.62,145.0,2.62,54.35
+2020-09-18 11:00:00,25.66,663.0,828.83,121.0,2.48,49.3
+2020-09-18 12:00:00,26.6,618.0,782.27,130.0,2.28,46.15
+2020-09-18 13:00:00,27.27,542.0,768.5,117.0,2.21,41.8
+2020-09-18 14:00:00,27.57,418.0,696.78,107.0,2.14,40.35
+2020-09-18 15:00:00,27.57,269.0,581.9,88.0,2.0,38.95
+2020-09-18 16:00:00,26.6,106.0,306.96,58.0,1.66,44.55
+2020-09-18 17:00:00,24.41,0.0,-0.0,0.0,2.28,50.7
+2020-09-18 18:00:00,22.4,0.0,-0.0,0.0,2.41,57.75
+2020-09-18 19:00:00,21.79,0.0,-0.0,0.0,2.62,55.65
+2020-09-18 20:00:00,20.76,0.0,-0.0,0.0,2.48,61.6
+2020-09-18 21:00:00,19.59,0.0,-0.0,0.0,2.34,65.85
+2020-09-18 22:00:00,18.49,0.0,-0.0,0.0,2.28,70.45
+2020-09-18 23:00:00,17.53,0.0,-0.0,0.0,2.21,72.9
+2020-09-19 00:00:00,16.6,0.0,-0.0,0.0,2.21,78.0
+2020-09-19 01:00:00,15.92,0.0,-0.0,0.0,2.21,80.65
+2020-09-19 02:00:00,15.43,0.0,-0.0,0.0,2.07,83.5
+2020-09-19 03:00:00,14.89,0.0,-0.0,0.0,1.86,86.45
+2020-09-19 04:00:00,14.57,0.0,-0.0,0.0,1.79,83.45
+2020-09-19 05:00:00,14.71,18.0,35.68,16.0,1.72,83.45
+2020-09-19 06:00:00,16.05,153.0,349.81,77.0,1.31,77.95
+2020-09-19 07:00:00,18.8,227.0,175.29,163.0,1.17,70.55
+2020-09-19 08:00:00,19.85,426.0,557.66,153.0,1.31,68.2
+2020-09-19 09:00:00,21.26,510.0,542.9,194.0,0.97,61.7
+2020-09-19 10:00:00,22.6,606.0,707.15,156.0,1.1,57.9
+2020-09-19 11:00:00,24.38,634.0,767.63,136.0,1.1,52.5
+2020-09-19 12:00:00,25.58,600.0,755.2,133.0,0.83,49.2
+2020-09-19 13:00:00,26.37,522.0,729.01,123.0,0.9,46.15
+2020-09-19 14:00:00,27.0,401.0,656.21,112.0,0.97,43.15
+2020-09-19 15:00:00,27.13,256.0,550.93,88.0,1.24,41.8
+2020-09-19 16:00:00,26.42,95.0,246.44,58.0,1.45,46.15
+2020-09-19 17:00:00,24.5,0.0,-0.0,0.0,2.14,52.5
+2020-09-19 18:00:00,22.48,0.0,-0.0,0.0,2.21,57.75
+2020-09-19 19:00:00,21.59,0.0,-0.0,0.0,2.41,57.65
+2020-09-19 20:00:00,20.75,0.0,-0.0,0.0,2.41,59.5
+2020-09-19 21:00:00,19.72,0.0,-0.0,0.0,2.34,61.4
+2020-09-19 22:00:00,18.85,0.0,-0.0,0.0,2.21,63.5
+2020-09-19 23:00:00,18.07,0.0,-0.0,0.0,2.28,65.65
+2020-09-20 00:00:00,17.78,0.0,-0.0,0.0,2.28,67.95
+2020-09-20 01:00:00,17.25,0.0,-0.0,0.0,2.28,70.3
+2020-09-20 02:00:00,16.73,0.0,-0.0,0.0,2.28,75.3
+2020-09-20 03:00:00,16.21,0.0,-0.0,0.0,2.21,77.95
+2020-09-20 04:00:00,15.62,0.0,-0.0,0.0,2.14,80.65
+2020-09-20 05:00:00,15.26,16.0,38.61,14.0,2.07,83.5
+2020-09-20 06:00:00,16.15,155.0,394.38,71.0,1.79,83.6
+2020-09-20 07:00:00,20.19,298.0,512.81,113.0,1.1,73.2
+2020-09-20 08:00:00,22.99,436.0,626.76,132.0,1.1,62.05
+2020-09-20 09:00:00,24.54,541.0,689.36,143.0,1.45,56.25
+2020-09-20 10:00:00,26.18,446.0,237.57,296.0,1.86,49.45
+2020-09-20 11:00:00,27.31,477.0,281.26,296.0,2.62,46.4
+2020-09-20 12:00:00,28.08,499.0,409.54,248.0,3.03,40.5
+2020-09-20 13:00:00,28.56,402.0,300.97,239.0,2.9,37.9
+2020-09-20 14:00:00,28.85,331.0,356.78,176.0,2.76,35.45
+2020-09-20 15:00:00,28.63,214.0,317.93,119.0,2.34,34.2
+2020-09-20 16:00:00,27.46,85.0,201.54,56.0,1.52,41.8
+2020-09-20 17:00:00,25.5,0.0,-0.0,0.0,1.86,45.9
+2020-09-20 18:00:00,23.29,0.0,-0.0,0.0,2.21,52.25
+2020-09-20 19:00:00,22.04,0.0,-0.0,0.0,2.41,53.75
+2020-09-20 20:00:00,21.16,0.0,-0.0,0.0,2.48,55.55
+2020-09-20 21:00:00,20.32,0.0,-0.0,0.0,2.48,59.35
+2020-09-20 22:00:00,19.61,0.0,-0.0,0.0,2.48,61.4
+2020-09-20 23:00:00,19.07,0.0,-0.0,0.0,2.55,65.75
+2020-09-21 00:00:00,18.73,0.0,-0.0,0.0,2.62,65.75
+2020-09-21 01:00:00,18.44,0.0,-0.0,0.0,2.62,68.05
+2020-09-21 02:00:00,18.1,0.0,-0.0,0.0,2.69,68.05
+2020-09-21 03:00:00,17.83,0.0,-0.0,0.0,2.76,70.35
+2020-09-21 04:00:00,17.73,0.0,-0.0,0.0,3.03,70.35
+2020-09-21 05:00:00,17.68,7.0,0.0,7.0,3.24,70.35
+2020-09-21 06:00:00,18.5,131.0,229.99,83.0,3.52,70.45
+2020-09-21 07:00:00,20.42,277.0,415.29,129.0,3.31,65.95
+2020-09-21 08:00:00,22.6,363.0,337.16,201.0,3.93,57.9
+2020-09-21 09:00:00,24.46,508.0,571.09,181.0,4.34,50.7
+2020-09-21 10:00:00,26.11,600.0,727.96,144.0,4.76,43.05
+2020-09-21 11:00:00,27.51,440.0,211.51,305.0,4.76,38.95
+2020-09-21 12:00:00,28.62,573.0,693.16,152.0,4.76,35.3
+2020-09-21 13:00:00,29.2,266.0,52.26,238.0,4.97,30.9
+2020-09-21 14:00:00,28.77,322.0,338.42,177.0,5.17,30.75
+2020-09-21 15:00:00,27.49,66.0,0.0,66.0,4.62,36.3
+2020-09-21 16:00:00,26.25,19.0,0.0,19.0,5.03,38.7
+2020-09-21 17:00:00,24.02,0.0,-0.0,0.0,5.66,45.5
+2020-09-21 18:00:00,19.72,0.0,-0.0,0.0,5.17,68.2
+2020-09-21 19:00:00,15.6,0.0,-0.0,0.0,4.9,89.6
+2020-09-21 20:00:00,13.89,0.0,-0.0,0.0,3.72,89.45
+2020-09-21 21:00:00,13.36,0.0,-0.0,0.0,3.86,80.35
+2020-09-21 22:00:00,13.29,0.0,-0.0,0.0,3.93,77.5
+2020-09-21 23:00:00,13.34,0.0,-0.0,0.0,3.93,74.75
+2020-09-22 00:00:00,13.33,0.0,-0.0,0.0,3.86,69.55
+2020-09-22 01:00:00,13.26,0.0,-0.0,0.0,3.93,62.3
+2020-09-22 02:00:00,12.92,0.0,-0.0,0.0,4.07,59.95
+2020-09-22 03:00:00,12.77,0.0,-0.0,0.0,4.21,57.75
+2020-09-22 04:00:00,12.62,0.0,-0.0,0.0,4.28,57.75
+2020-09-22 05:00:00,12.46,13.0,46.21,11.0,4.34,59.85
+2020-09-22 06:00:00,12.94,160.0,474.56,63.0,4.0,57.75
+2020-09-22 07:00:00,13.42,285.0,443.23,129.0,6.07,62.3
+2020-09-22 08:00:00,13.96,440.0,649.28,131.0,6.21,58.0
+2020-09-22 09:00:00,14.85,512.0,565.34,191.0,6.28,50.25
+2020-09-22 10:00:00,15.64,407.0,160.93,307.0,5.72,45.15
+2020-09-22 11:00:00,16.35,470.0,263.83,303.0,5.31,42.05
+2020-09-22 12:00:00,16.91,393.0,159.52,297.0,5.1,37.65
+2020-09-22 13:00:00,17.19,306.0,98.11,254.0,4.69,35.05
+2020-09-22 14:00:00,17.62,199.0,40.24,182.0,4.48,32.65
+2020-09-22 15:00:00,17.95,80.0,0.0,80.0,4.48,29.1
+2020-09-22 16:00:00,17.53,46.0,15.22,44.0,3.24,29.1
+2020-09-22 17:00:00,16.89,0.0,-0.0,0.0,2.9,31.15
+2020-09-22 18:00:00,16.47,0.0,-0.0,0.0,3.1,32.2
+2020-09-22 19:00:00,15.35,0.0,-0.0,0.0,2.28,40.2
+2020-09-22 20:00:00,15.05,0.0,-0.0,0.0,2.9,41.75
+2020-09-22 21:00:00,14.66,0.0,-0.0,0.0,3.17,44.9
+2020-09-22 22:00:00,14.3,0.0,-0.0,0.0,3.24,50.1
+2020-09-22 23:00:00,13.89,0.0,-0.0,0.0,3.38,55.9
+2020-09-23 00:00:00,13.34,0.0,-0.0,0.0,3.31,64.65
+2020-09-23 01:00:00,12.45,0.0,-0.0,0.0,2.97,69.35
+2020-09-23 02:00:00,12.43,0.0,-0.0,0.0,2.83,71.95
+2020-09-23 03:00:00,12.32,0.0,-0.0,0.0,2.76,71.95
+2020-09-23 04:00:00,12.08,0.0,-0.0,0.0,2.55,71.95
+2020-09-23 05:00:00,12.1,1.0,0.0,1.0,2.41,71.95
+2020-09-23 06:00:00,12.13,65.0,10.0,63.0,1.66,71.95
+2020-09-23 07:00:00,12.25,113.0,5.76,111.0,1.52,74.6
+2020-09-23 08:00:00,12.27,117.0,0.0,117.0,1.52,77.35
+2020-09-23 09:00:00,12.51,180.0,1.78,179.0,1.72,77.45
+2020-09-23 10:00:00,12.65,191.0,0.0,191.0,1.72,77.45
+2020-09-23 11:00:00,12.78,83.0,0.0,83.0,1.93,80.3
+2020-09-23 12:00:00,12.7,134.0,0.0,134.0,2.28,83.25
+2020-09-23 13:00:00,12.62,118.0,0.0,118.0,2.83,86.25
+2020-09-23 14:00:00,12.68,34.0,0.0,34.0,3.66,86.25
+2020-09-23 15:00:00,12.96,28.0,0.0,28.0,4.0,89.4
+2020-09-23 16:00:00,13.89,22.0,0.0,22.0,4.28,89.45
+2020-09-23 17:00:00,16.39,0.0,-0.0,0.0,4.28,86.55
+2020-09-23 18:00:00,17.26,0.0,-0.0,0.0,4.21,86.65
+2020-09-23 19:00:00,10.57,0.0,-0.0,0.0,2.9,95.9
+2020-09-23 20:00:00,9.96,0.0,-0.0,0.0,6.0,95.9
+2020-09-23 21:00:00,8.78,0.0,-0.0,0.0,6.69,99.4
+2020-09-23 22:00:00,7.92,0.0,-0.0,0.0,5.45,95.8
+2020-09-23 23:00:00,7.81,0.0,-0.0,0.0,5.59,92.4
+2020-09-24 00:00:00,7.92,0.0,-0.0,0.0,5.52,89.1
+2020-09-24 01:00:00,8.33,0.0,-0.0,0.0,5.45,89.1
+2020-09-24 02:00:00,8.05,0.0,-0.0,0.0,5.93,89.1
+2020-09-24 03:00:00,7.95,0.0,-0.0,0.0,6.14,89.1
+2020-09-24 04:00:00,7.71,0.0,-0.0,0.0,5.79,89.05
+2020-09-24 05:00:00,7.63,4.0,0.0,4.0,5.79,89.05
+2020-09-24 06:00:00,7.69,121.0,204.37,81.0,6.07,85.85
+2020-09-24 07:00:00,8.21,208.0,145.75,158.0,4.83,89.1
+2020-09-24 08:00:00,9.02,296.0,156.43,223.0,5.1,85.95
+2020-09-24 09:00:00,10.1,327.0,100.34,271.0,5.72,79.95
+2020-09-24 10:00:00,11.01,444.0,242.15,296.0,6.07,74.45
+2020-09-24 11:00:00,11.87,244.0,8.04,239.0,6.55,66.75
+2020-09-24 12:00:00,12.28,214.0,5.08,211.0,6.69,59.85
+2020-09-24 13:00:00,12.57,418.0,374.28,224.0,6.69,53.6
+2020-09-24 14:00:00,12.66,284.0,226.61,191.0,6.83,47.85
+2020-09-24 15:00:00,12.29,161.0,138.62,123.0,6.41,47.75
+2020-09-24 16:00:00,11.87,18.0,0.0,18.0,5.66,47.6
+2020-09-24 17:00:00,11.15,0.0,-0.0,0.0,5.52,49.3
+2020-09-24 18:00:00,10.38,0.0,-0.0,0.0,5.66,57.15
+2020-09-24 19:00:00,8.93,0.0,-0.0,0.0,4.97,74.15
+2020-09-24 20:00:00,8.14,0.0,-0.0,0.0,4.69,74.05
+2020-09-24 21:00:00,7.43,0.0,-0.0,0.0,4.28,79.7
+2020-09-24 22:00:00,7.05,0.0,-0.0,0.0,5.03,82.65
+2020-09-24 23:00:00,6.63,0.0,-0.0,0.0,4.21,85.75
+2020-09-25 00:00:00,6.45,0.0,-0.0,0.0,4.0,82.6
+2020-09-25 01:00:00,6.37,0.0,-0.0,0.0,3.86,85.7
+2020-09-25 02:00:00,6.36,0.0,-0.0,0.0,3.72,82.55
+2020-09-25 03:00:00,6.11,0.0,-0.0,0.0,3.59,82.55
+2020-09-25 04:00:00,5.92,0.0,-0.0,0.0,3.59,82.55
+2020-09-25 05:00:00,5.99,6.0,0.0,6.0,3.52,82.55
+2020-09-25 06:00:00,6.21,147.0,433.76,64.0,3.31,85.7
+2020-09-25 07:00:00,6.91,250.0,307.18,146.0,4.76,82.6
+2020-09-25 08:00:00,8.08,321.0,216.45,221.0,4.55,71.35
+2020-09-25 09:00:00,9.27,351.0,139.18,274.0,4.21,63.8
+2020-09-25 10:00:00,10.16,449.0,254.1,295.0,4.07,55.05
+2020-09-25 11:00:00,11.16,327.0,56.74,292.0,4.07,49.3
+2020-09-25 12:00:00,11.64,407.0,198.31,291.0,3.79,44.1
+2020-09-25 13:00:00,12.1,389.0,290.76,240.0,3.66,40.95
+2020-09-25 14:00:00,12.27,324.0,383.35,169.0,3.38,39.4
+2020-09-25 15:00:00,12.27,199.0,328.43,111.0,3.17,37.9
+2020-09-25 16:00:00,11.82,67.0,204.29,44.0,2.34,39.25
+2020-09-25 17:00:00,10.55,0.0,-0.0,0.0,1.52,45.55
+2020-09-25 18:00:00,8.64,0.0,-0.0,0.0,1.45,61.3
+2020-09-25 19:00:00,7.05,0.0,-0.0,0.0,1.72,63.5
+2020-09-25 20:00:00,6.21,0.0,-0.0,0.0,1.72,68.3
+2020-09-25 21:00:00,5.12,0.0,-0.0,0.0,1.86,73.55
+2020-09-25 22:00:00,4.31,0.0,-0.0,0.0,1.86,79.2
+2020-09-25 23:00:00,3.93,0.0,-0.0,0.0,1.79,79.2
+2020-09-26 00:00:00,3.61,0.0,-0.0,0.0,1.86,82.25
+2020-09-26 01:00:00,2.98,0.0,-0.0,0.0,1.86,82.2
+2020-09-26 02:00:00,2.65,0.0,-0.0,0.0,1.93,85.35
+2020-09-26 03:00:00,2.68,0.0,-0.0,0.0,2.14,85.35
+2020-09-26 04:00:00,2.91,0.0,-0.0,0.0,2.21,82.2
+2020-09-26 05:00:00,3.25,6.0,0.0,6.0,2.28,79.1
+2020-09-26 06:00:00,4.62,77.0,37.44,70.0,2.21,73.45
+2020-09-26 07:00:00,7.31,262.0,401.15,128.0,2.28,68.5
+2020-09-26 08:00:00,9.81,381.0,450.48,175.0,3.1,57.05
+2020-09-26 09:00:00,11.27,476.0,494.25,205.0,3.38,49.3
+2020-09-26 10:00:00,12.68,588.0,728.92,150.0,3.66,42.7
+2020-09-26 11:00:00,14.11,530.0,474.28,240.0,3.45,38.45
+2020-09-26 12:00:00,15.34,516.0,528.24,210.0,3.31,34.5
+2020-09-26 13:00:00,16.1,448.0,534.97,177.0,3.24,31.0
+2020-09-26 14:00:00,16.3,200.0,55.24,178.0,3.17,29.8
+2020-09-26 15:00:00,16.05,159.0,164.28,116.0,2.55,33.5
+2020-09-26 16:00:00,15.03,43.0,47.03,38.0,2.41,35.85
+2020-09-26 17:00:00,13.57,0.0,-0.0,0.0,2.48,39.8
+2020-09-26 18:00:00,12.58,0.0,-0.0,0.0,2.69,41.1
+2020-09-26 19:00:00,12.09,0.0,-0.0,0.0,2.9,45.95
+2020-09-26 20:00:00,11.85,0.0,-0.0,0.0,3.24,45.8
+2020-09-26 21:00:00,11.7,0.0,-0.0,0.0,3.38,42.4
+2020-09-26 22:00:00,11.59,0.0,-0.0,0.0,3.38,40.8
+2020-09-26 23:00:00,11.5,0.0,-0.0,0.0,3.38,40.8
+2020-09-27 00:00:00,11.58,0.0,-0.0,0.0,3.38,40.8
+2020-09-27 01:00:00,11.62,0.0,-0.0,0.0,3.31,40.8
+2020-09-27 02:00:00,11.67,0.0,-0.0,0.0,3.31,40.8
+2020-09-27 03:00:00,11.74,0.0,-0.0,0.0,3.17,42.4
+2020-09-27 04:00:00,11.72,0.0,-0.0,0.0,2.97,42.4
+2020-09-27 05:00:00,11.63,0.0,0.0,0.0,2.83,44.1
+2020-09-27 06:00:00,11.82,93.0,109.56,73.0,2.62,45.8
+2020-09-27 07:00:00,13.38,108.0,6.07,106.0,2.76,49.85
+2020-09-27 08:00:00,13.98,186.0,19.89,177.0,2.48,51.9
+2020-09-27 09:00:00,14.95,188.0,3.68,186.0,2.69,50.25
+2020-09-27 10:00:00,15.84,310.0,60.43,274.0,2.76,50.5
+2020-09-27 11:00:00,17.29,466.0,325.08,269.0,2.76,52.75
+2020-09-27 12:00:00,18.37,524.0,615.42,171.0,2.76,59.05
+2020-09-27 13:00:00,19.3,465.0,675.11,127.0,2.83,63.5
+2020-09-27 14:00:00,19.88,351.0,629.81,104.0,2.69,61.4
+2020-09-27 15:00:00,20.12,207.0,504.8,78.0,2.21,59.35
+2020-09-27 16:00:00,19.58,55.0,169.88,38.0,1.17,63.6
+2020-09-27 17:00:00,17.91,0.0,-0.0,0.0,1.45,70.35
+2020-09-27 18:00:00,15.65,0.0,-0.0,0.0,2.07,77.85
+2020-09-27 19:00:00,14.96,0.0,-0.0,0.0,2.34,80.55
+2020-09-27 20:00:00,14.23,0.0,-0.0,0.0,2.41,77.65
+2020-09-27 21:00:00,13.65,0.0,-0.0,0.0,2.41,74.85
+2020-09-27 22:00:00,13.07,0.0,-0.0,0.0,2.34,72.1
+2020-09-27 23:00:00,12.37,0.0,-0.0,0.0,2.34,69.35
+2020-09-28 00:00:00,11.64,0.0,-0.0,0.0,2.34,66.75
+2020-09-28 01:00:00,11.01,0.0,-0.0,0.0,2.41,66.65
+2020-09-28 02:00:00,10.56,0.0,-0.0,0.0,2.55,64.1
+2020-09-28 03:00:00,10.27,0.0,-0.0,0.0,2.69,66.45
+2020-09-28 04:00:00,9.88,0.0,-0.0,0.0,2.76,68.9
+2020-09-28 05:00:00,9.47,0.0,0.0,0.0,2.76,68.9
+2020-09-28 06:00:00,9.8,121.0,308.79,66.0,2.55,71.5
+2020-09-28 07:00:00,12.37,267.0,483.19,110.0,2.28,69.35
+2020-09-28 08:00:00,14.11,213.0,42.43,194.0,2.9,62.55
+2020-09-28 09:00:00,14.79,103.0,0.0,103.0,3.31,67.35
+2020-09-28 10:00:00,14.54,72.0,0.0,72.0,3.72,75.0
+2020-09-28 11:00:00,14.29,82.0,0.0,82.0,3.66,77.65
+2020-09-28 12:00:00,14.25,70.0,0.0,70.0,3.38,77.65
+2020-09-28 13:00:00,14.22,70.0,0.0,70.0,2.97,77.65
+2020-09-28 14:00:00,14.12,120.0,2.59,119.0,3.1,74.95
+2020-09-28 15:00:00,13.96,102.0,28.07,95.0,3.31,67.15
+2020-09-28 16:00:00,13.6,30.0,10.66,29.0,2.9,60.2
+2020-09-28 17:00:00,12.74,0.0,-0.0,0.0,2.9,55.65
+2020-09-28 18:00:00,11.98,0.0,-0.0,0.0,3.03,51.5
+2020-09-28 19:00:00,10.67,0.0,-0.0,0.0,2.97,55.15
+2020-09-28 20:00:00,9.97,0.0,-0.0,0.0,2.83,55.05
+2020-09-28 21:00:00,9.19,0.0,-0.0,0.0,2.34,59.15
+2020-09-28 22:00:00,8.12,0.0,-0.0,0.0,1.93,63.7
+2020-09-28 23:00:00,6.96,0.0,-0.0,0.0,1.93,68.5
+2020-09-29 00:00:00,5.92,0.0,-0.0,0.0,1.86,73.7
+2020-09-29 01:00:00,5.15,0.0,-0.0,0.0,1.79,79.35
+2020-09-29 02:00:00,4.72,0.0,-0.0,0.0,1.86,82.35
+2020-09-29 03:00:00,4.29,0.0,-0.0,0.0,1.86,82.3
+2020-09-29 04:00:00,4.16,0.0,-0.0,0.0,1.86,82.3
+2020-09-29 05:00:00,3.97,0.0,0.0,0.0,1.79,82.3
+2020-09-29 06:00:00,4.66,131.0,420.34,58.0,1.45,85.55
+2020-09-29 07:00:00,7.03,283.0,596.27,92.0,1.45,79.65
+2020-09-29 08:00:00,8.68,419.0,686.22,115.0,1.52,76.85
+2020-09-29 09:00:00,9.94,520.0,723.73,134.0,1.24,74.2
+2020-09-29 10:00:00,10.99,519.0,505.81,223.0,1.38,61.85
+2020-09-29 11:00:00,11.47,498.0,408.39,255.0,1.52,57.55
+2020-09-29 12:00:00,11.79,407.0,238.38,273.0,1.17,55.4
+2020-09-29 13:00:00,12.09,441.0,560.56,167.0,0.76,51.5
+2020-09-29 14:00:00,12.38,353.0,663.15,101.0,0.41,49.6
+2020-09-29 15:00:00,12.23,200.0,493.5,80.0,0.28,47.75
+2020-09-29 16:00:00,11.9,50.0,194.06,33.0,0.28,49.45
+2020-09-29 17:00:00,10.31,0.0,-0.0,0.0,1.03,66.45
+2020-09-29 18:00:00,8.86,0.0,-0.0,0.0,1.31,68.7
+2020-09-29 19:00:00,7.08,0.0,-0.0,0.0,1.79,71.15
+2020-09-29 20:00:00,5.94,0.0,-0.0,0.0,2.0,76.55
+2020-09-29 21:00:00,5.38,0.0,-0.0,0.0,2.14,82.4
+2020-09-29 22:00:00,5.08,0.0,-0.0,0.0,2.28,79.35
+2020-09-29 23:00:00,4.93,0.0,-0.0,0.0,2.34,79.35
+2020-09-30 00:00:00,4.8,0.0,-0.0,0.0,2.34,79.3
+2020-09-30 01:00:00,4.59,0.0,-0.0,0.0,2.34,79.3
+2020-09-30 02:00:00,4.51,0.0,-0.0,0.0,2.41,76.3
+2020-09-30 03:00:00,4.57,0.0,-0.0,0.0,2.55,76.3
+2020-09-30 04:00:00,4.74,0.0,-0.0,0.0,2.69,73.45
+2020-09-30 05:00:00,4.89,0.0,0.0,0.0,2.76,70.8
+2020-09-30 06:00:00,5.62,128.0,431.44,55.0,2.69,70.85
+2020-09-30 07:00:00,7.71,284.0,630.33,85.0,2.41,66.05
+2020-09-30 08:00:00,10.29,423.0,727.99,104.0,2.9,57.15
+2020-09-30 09:00:00,12.2,523.0,762.81,120.0,2.76,49.6
+2020-09-30 10:00:00,13.74,578.0,762.18,136.0,2.55,42.95
+2020-09-30 11:00:00,15.01,583.0,737.93,148.0,2.34,38.7
+2020-09-30 12:00:00,15.89,522.0,623.67,175.0,2.48,37.4
+2020-09-30 13:00:00,16.39,454.0,648.23,141.0,2.41,36.15
+2020-09-30 14:00:00,16.48,343.0,633.84,106.0,2.21,36.15
+2020-09-30 15:00:00,16.19,198.0,527.48,73.0,2.0,36.15
+2020-09-30 16:00:00,11.83,43.0,159.73,30.0,2.36,48.24
+2020-09-30 17:00:00,11.37,0.0,-0.0,0.0,2.31,51.71
+2020-09-30 18:00:00,10.92,0.0,-0.0,0.0,2.25,55.17
+2020-09-30 19:00:00,10.47,0.0,-0.0,0.0,2.19,58.64
+2020-09-30 20:00:00,10.02,0.0,-0.0,0.0,2.14,62.1
+2020-09-30 21:00:00,9.57,0.0,-0.0,0.0,2.08,65.56
+2020-09-30 22:00:00,9.12,0.0,-0.0,0.0,2.03,69.03
+2020-09-30 23:00:00,8.67,0.0,-0.0,0.0,1.97,72.49
+2020-10-01 00:00:00,8.22,0.0,-0.0,0.0,1.92,75.96
+2020-10-01 01:00:00,7.77,0.0,-0.0,0.0,1.86,79.42
+2020-10-01 02:00:00,7.32,0.0,-0.0,0.0,1.8,82.89
+2020-10-01 03:00:00,6.87,0.0,-0.0,0.0,1.75,86.35
+2020-10-01 04:00:00,6.42,0.0,-0.0,0.0,1.69,89.81
+2020-10-01 05:00:00,5.96,0.0,0.0,0.0,1.64,93.28
+2020-10-01 06:00:00,5.51,121.0,406.77,54.0,1.58,96.74
+2020-10-01 07:00:00,5.06,270.0,581.87,89.0,1.53,100.0
+2020-10-01 08:00:00,8.89,417.0,740.74,96.0,2.14,85.95
+2020-10-01 09:00:00,10.44,532.0,837.09,94.0,2.07,77.15
+2020-10-01 10:00:00,11.21,588.0,844.06,103.0,1.79,74.45
+2020-10-01 11:00:00,12.0,581.0,770.63,131.0,1.72,69.35
+2020-10-01 12:00:00,12.64,573.0,879.02,89.0,1.79,64.55
+2020-10-01 13:00:00,12.8,477.0,803.11,94.0,2.0,64.55
+2020-10-01 14:00:00,12.78,345.0,701.44,87.0,2.21,64.55
+2020-10-01 15:00:00,12.54,190.0,515.6,71.0,2.21,66.95
+2020-10-01 16:00:00,11.91,34.0,93.1,27.0,2.0,69.35
+2020-10-01 17:00:00,10.77,0.0,-0.0,0.0,2.0,77.15
+2020-10-01 18:00:00,9.62,0.0,-0.0,0.0,2.07,82.9
+2020-10-01 19:00:00,9.22,0.0,-0.0,0.0,2.34,85.95
+2020-10-01 20:00:00,8.47,0.0,-0.0,0.0,2.41,89.1
+2020-10-01 21:00:00,8.02,0.0,-0.0,0.0,2.48,89.05
+2020-10-01 22:00:00,7.82,0.0,-0.0,0.0,2.55,92.35
+2020-10-01 23:00:00,7.82,0.0,-0.0,0.0,2.62,89.0
+2020-10-02 00:00:00,7.81,0.0,-0.0,0.0,2.62,85.8
+2020-10-02 01:00:00,7.58,0.0,-0.0,0.0,2.69,82.65
+2020-10-02 02:00:00,7.83,0.0,-0.0,0.0,2.76,82.65
+2020-10-02 03:00:00,7.91,0.0,-0.0,0.0,2.83,79.7
+2020-10-02 04:00:00,8.09,0.0,-0.0,0.0,2.97,79.7
+2020-10-02 05:00:00,8.35,0.0,-0.0,0.0,3.03,79.7
+2020-10-02 06:00:00,8.67,57.0,18.73,54.0,3.03,76.85
+2020-10-02 07:00:00,8.62,255.0,528.72,93.0,3.1,89.1
+2020-10-02 08:00:00,9.73,263.0,147.03,200.0,3.31,82.9
+2020-10-02 09:00:00,10.63,385.0,293.35,233.0,3.45,80.05
+2020-10-02 10:00:00,11.85,469.0,418.08,231.0,3.66,77.3
+2020-10-02 11:00:00,12.27,321.0,79.53,275.0,3.66,74.6
+2020-10-02 12:00:00,12.81,523.0,728.67,126.0,3.66,74.7
+2020-10-02 13:00:00,13.23,208.0,25.48,196.0,3.79,72.1
+2020-10-02 14:00:00,13.24,126.0,5.53,124.0,3.45,74.75
+2020-10-02 15:00:00,13.18,79.0,13.35,76.0,3.03,74.75
+2020-10-02 16:00:00,12.68,11.0,0.0,11.0,2.69,77.45
+2020-10-02 17:00:00,12.24,0.0,-0.0,0.0,2.76,80.2
+2020-10-02 18:00:00,12.03,0.0,-0.0,0.0,2.97,77.35
+2020-10-02 19:00:00,11.7,0.0,-0.0,0.0,3.1,83.1
+2020-10-02 20:00:00,11.58,0.0,-0.0,0.0,3.17,83.1
+2020-10-02 21:00:00,11.44,0.0,-0.0,0.0,3.24,83.1
+2020-10-02 22:00:00,11.19,0.0,-0.0,0.0,3.31,86.1
+2020-10-02 23:00:00,10.62,0.0,-0.0,0.0,3.31,89.25
+2020-10-03 00:00:00,10.26,0.0,-0.0,0.0,3.31,92.5
+2020-10-03 01:00:00,9.22,0.0,-0.0,0.0,3.38,92.45
+2020-10-03 02:00:00,8.92,0.0,-0.0,0.0,3.45,92.45
+2020-10-03 03:00:00,8.71,0.0,-0.0,0.0,3.59,95.85
+2020-10-03 04:00:00,8.73,0.0,-0.0,0.0,3.66,95.85
+2020-10-03 05:00:00,8.7,0.0,-0.0,0.0,3.79,95.85
+2020-10-03 06:00:00,8.96,93.0,211.96,60.0,4.07,92.45
+2020-10-03 07:00:00,9.75,233.0,417.61,107.0,4.41,92.45
+2020-10-03 08:00:00,10.86,294.0,247.88,189.0,4.83,89.25
+2020-10-03 09:00:00,11.7,424.0,444.42,196.0,4.9,83.1
+2020-10-03 10:00:00,12.53,546.0,757.21,119.0,5.24,77.45
+2020-10-03 11:00:00,13.66,455.0,368.38,244.0,5.03,74.85
+2020-10-03 12:00:00,13.93,190.0,3.71,188.0,5.1,74.95
+2020-10-03 13:00:00,14.29,201.0,23.66,190.0,5.59,72.3
+2020-10-03 14:00:00,14.35,169.0,47.8,152.0,5.66,72.3
+2020-10-03 15:00:00,14.11,143.0,247.15,89.0,5.45,72.3
+2020-10-03 16:00:00,13.48,23.0,47.72,20.0,4.9,74.85
+2020-10-03 17:00:00,12.55,0.0,-0.0,0.0,5.17,77.45
+2020-10-03 18:00:00,11.91,0.0,-0.0,0.0,5.52,77.35
+2020-10-03 19:00:00,10.38,0.0,-0.0,0.0,5.59,77.15
+2020-10-03 20:00:00,10.1,0.0,-0.0,0.0,5.72,79.95
+2020-10-03 21:00:00,9.94,0.0,-0.0,0.0,5.79,79.95
+2020-10-03 22:00:00,9.89,0.0,-0.0,0.0,5.79,79.95
+2020-10-03 23:00:00,9.8,0.0,-0.0,0.0,5.66,82.9
+2020-10-04 00:00:00,9.84,0.0,-0.0,0.0,5.66,82.9
+2020-10-04 01:00:00,9.75,0.0,-0.0,0.0,5.59,82.9
+2020-10-04 02:00:00,9.66,0.0,-0.0,0.0,5.45,82.9
+2020-10-04 03:00:00,9.58,0.0,-0.0,0.0,5.38,79.9
+2020-10-04 04:00:00,9.48,0.0,-0.0,0.0,5.31,79.9
+2020-10-04 05:00:00,9.35,0.0,-0.0,0.0,5.45,79.85
+2020-10-04 06:00:00,9.43,112.0,443.25,45.0,5.52,77.0
+2020-10-04 07:00:00,9.94,257.0,606.04,77.0,4.9,79.95
+2020-10-04 08:00:00,10.98,399.0,745.19,87.0,5.59,77.2
+2020-10-04 09:00:00,12.07,454.0,576.9,161.0,5.79,74.6
+2020-10-04 10:00:00,13.51,243.0,21.48,231.0,6.41,69.65
+2020-10-04 11:00:00,14.12,118.0,0.0,118.0,6.14,69.75
+2020-10-04 12:00:00,14.44,78.0,0.0,78.0,6.28,69.85
+2020-10-04 13:00:00,14.41,78.0,0.0,78.0,6.14,72.3
+2020-10-04 14:00:00,14.07,51.0,0.0,51.0,5.86,72.3
+2020-10-04 15:00:00,13.59,56.0,0.0,56.0,5.52,72.2
+2020-10-04 16:00:00,12.91,17.0,17.62,16.0,5.72,72.1
+2020-10-04 17:00:00,12.37,0.0,-0.0,0.0,5.72,77.35
+2020-10-04 18:00:00,12.18,0.0,-0.0,0.0,5.66,77.35
+2020-10-04 19:00:00,11.12,0.0,-0.0,0.0,5.59,80.1
+2020-10-04 20:00:00,11.1,0.0,-0.0,0.0,5.66,83.05
+2020-10-04 21:00:00,11.15,0.0,-0.0,0.0,5.52,83.05
+2020-10-04 22:00:00,11.22,0.0,-0.0,0.0,5.31,83.05
+2020-10-04 23:00:00,11.24,0.0,-0.0,0.0,5.03,86.1
+2020-10-05 00:00:00,11.23,0.0,-0.0,0.0,4.83,86.1
+2020-10-05 01:00:00,11.22,0.0,-0.0,0.0,4.69,86.1
+2020-10-05 02:00:00,11.15,0.0,-0.0,0.0,4.55,86.1
+2020-10-05 03:00:00,11.2,0.0,-0.0,0.0,4.41,86.1
+2020-10-05 04:00:00,11.08,0.0,-0.0,0.0,4.34,89.3
+2020-10-05 05:00:00,11.06,0.0,-0.0,0.0,4.28,89.3
+2020-10-05 06:00:00,11.23,67.0,75.03,56.0,4.14,89.3
+2020-10-05 07:00:00,10.92,163.0,119.75,128.0,3.66,86.1
+2020-10-05 08:00:00,11.66,291.0,258.61,184.0,3.86,86.15
+2020-10-05 09:00:00,12.62,430.0,503.26,177.0,4.21,80.3
+2020-10-05 10:00:00,13.53,401.0,260.33,257.0,4.07,77.6
+2020-10-05 11:00:00,14.24,323.0,96.16,269.0,4.07,74.95
+2020-10-05 12:00:00,14.7,185.0,3.79,183.0,4.14,75.0
+2020-10-05 13:00:00,15.06,189.0,19.87,180.0,4.0,72.45
+2020-10-05 14:00:00,14.92,109.0,2.91,108.0,3.72,75.0
+2020-10-05 15:00:00,14.68,99.0,67.88,85.0,3.38,75.0
+2020-10-05 16:00:00,14.15,15.0,19.75,14.0,3.17,77.65
+2020-10-05 17:00:00,13.58,0.0,-0.0,0.0,3.17,80.4
+2020-10-05 18:00:00,13.18,0.0,-0.0,0.0,3.17,80.35
+2020-10-05 19:00:00,11.83,0.0,-0.0,0.0,3.03,86.15
+2020-10-05 20:00:00,11.52,0.0,-0.0,0.0,3.24,86.15
+2020-10-05 21:00:00,11.27,0.0,-0.0,0.0,3.03,89.3
+2020-10-05 22:00:00,10.92,0.0,-0.0,0.0,3.03,89.3
+2020-10-05 23:00:00,10.51,0.0,-0.0,0.0,3.03,92.5
+2020-10-06 00:00:00,10.17,0.0,-0.0,0.0,3.1,95.9
+2020-10-06 01:00:00,9.99,0.0,-0.0,0.0,3.17,95.9
+2020-10-06 02:00:00,9.95,0.0,-0.0,0.0,3.1,95.9
+2020-10-06 03:00:00,9.93,0.0,-0.0,0.0,3.17,95.9
+2020-10-06 04:00:00,10.05,0.0,-0.0,0.0,3.17,95.9
+2020-10-06 05:00:00,10.05,0.0,-0.0,0.0,3.17,95.9
+2020-10-06 06:00:00,10.27,79.0,176.01,54.0,3.31,95.9
+2020-10-06 07:00:00,10.81,136.0,59.12,119.0,3.52,95.9
+2020-10-06 08:00:00,11.7,248.0,149.22,187.0,3.38,89.3
+2020-10-06 09:00:00,12.33,339.0,219.08,230.0,3.31,89.35
+2020-10-06 10:00:00,13.24,542.0,812.44,97.0,3.79,83.25
+2020-10-06 11:00:00,14.14,553.0,818.43,98.0,4.14,77.65
+2020-10-06 12:00:00,14.0,510.0,787.93,99.0,4.21,77.65
+2020-10-06 13:00:00,14.25,297.0,205.77,205.0,4.34,77.65
+2020-10-06 14:00:00,14.14,152.0,38.52,139.0,4.28,77.65
+2020-10-06 15:00:00,13.84,91.0,59.95,79.0,3.86,80.4
+2020-10-06 16:00:00,13.33,11.0,0.0,11.0,3.59,83.25
+2020-10-06 17:00:00,12.76,0.0,-0.0,0.0,3.66,86.25
+2020-10-06 18:00:00,12.5,0.0,-0.0,0.0,3.45,83.25
+2020-10-06 19:00:00,12.13,0.0,-0.0,0.0,3.52,86.2
+2020-10-06 20:00:00,11.91,0.0,-0.0,0.0,3.59,83.15
+2020-10-06 21:00:00,11.74,0.0,-0.0,0.0,3.52,86.15
+2020-10-06 22:00:00,11.41,0.0,-0.0,0.0,3.24,86.15
+2020-10-06 23:00:00,11.13,0.0,-0.0,0.0,2.76,89.3
+2020-10-07 00:00:00,11.1,0.0,-0.0,0.0,2.55,89.3
+2020-10-07 01:00:00,11.05,0.0,-0.0,0.0,2.55,89.3
+2020-10-07 02:00:00,11.01,0.0,-0.0,0.0,2.62,89.3
+2020-10-07 03:00:00,11.0,0.0,-0.0,0.0,2.62,89.3
+2020-10-07 04:00:00,10.97,0.0,-0.0,0.0,2.69,89.3
+2020-10-07 05:00:00,10.94,0.0,-0.0,0.0,2.69,89.3
+2020-10-07 06:00:00,11.02,65.0,87.3,53.0,2.76,89.3
+2020-10-07 07:00:00,11.68,166.0,152.06,123.0,2.21,89.3
+2020-10-07 08:00:00,12.64,248.0,153.53,186.0,2.55,86.25
+2020-10-07 09:00:00,13.34,149.0,0.0,149.0,2.97,83.25
+2020-10-07 10:00:00,13.97,106.0,0.0,106.0,2.83,77.65
+2020-10-07 11:00:00,14.38,121.0,0.0,121.0,2.97,77.65
+2020-10-07 12:00:00,14.73,64.0,0.0,64.0,3.1,75.0
+2020-10-07 13:00:00,14.93,111.0,0.0,111.0,3.03,72.45
+2020-10-07 14:00:00,15.16,136.0,24.14,128.0,3.17,72.45
+2020-10-07 15:00:00,15.22,112.0,164.86,80.0,2.76,72.45
+2020-10-07 16:00:00,14.9,10.0,0.0,10.0,2.48,75.0
+2020-10-07 17:00:00,14.16,0.0,-0.0,0.0,2.48,77.65
+2020-10-07 18:00:00,13.48,0.0,-0.0,0.0,2.69,77.6
+2020-10-07 19:00:00,12.46,0.0,-0.0,0.0,2.62,80.3
+2020-10-07 20:00:00,11.95,0.0,-0.0,0.0,2.9,80.2
+2020-10-07 21:00:00,11.62,0.0,-0.0,0.0,3.1,80.15
+2020-10-07 22:00:00,11.28,0.0,-0.0,0.0,3.17,83.05
+2020-10-07 23:00:00,10.72,0.0,-0.0,0.0,3.17,83.0
+2020-10-08 00:00:00,10.27,0.0,-0.0,0.0,3.31,86.0
+2020-10-08 01:00:00,9.82,0.0,-0.0,0.0,3.38,85.95
+2020-10-08 02:00:00,9.63,0.0,-0.0,0.0,3.45,85.95
+2020-10-08 03:00:00,9.37,0.0,-0.0,0.0,3.52,85.95
+2020-10-08 04:00:00,9.15,0.0,-0.0,0.0,3.59,89.1
+2020-10-08 05:00:00,8.94,0.0,-0.0,0.0,3.59,89.1
+2020-10-08 06:00:00,9.07,63.0,82.79,52.0,3.66,89.1
+2020-10-08 07:00:00,10.14,172.0,165.47,126.0,3.1,89.2
+2020-10-08 08:00:00,11.25,313.0,366.07,167.0,4.0,86.1
+2020-10-08 09:00:00,12.22,489.0,804.73,97.0,4.34,80.2
+2020-10-08 10:00:00,13.33,543.0,812.12,107.0,4.28,74.75
+2020-10-08 11:00:00,14.46,556.0,828.03,105.0,4.55,67.35
+2020-10-08 12:00:00,15.32,509.0,788.25,107.0,4.55,65.05
+2020-10-08 13:00:00,15.81,430.0,776.65,92.0,4.48,60.65
+2020-10-08 14:00:00,15.76,290.0,596.19,96.0,4.28,60.65
+2020-10-08 15:00:00,15.17,153.0,515.77,56.0,3.72,62.75
+2020-10-08 16:00:00,13.99,9.0,0.0,9.0,3.72,64.85
+2020-10-08 17:00:00,12.79,0.0,-0.0,0.0,3.86,69.45
+2020-10-08 18:00:00,12.04,0.0,-0.0,0.0,4.07,71.95
+2020-10-08 19:00:00,11.54,0.0,-0.0,0.0,4.28,71.85
+2020-10-08 20:00:00,11.08,0.0,-0.0,0.0,4.34,71.75
+2020-10-08 21:00:00,10.6,0.0,-0.0,0.0,4.34,71.7
+2020-10-08 22:00:00,10.1,0.0,-0.0,0.0,4.28,74.3
+2020-10-08 23:00:00,9.59,0.0,-0.0,0.0,4.07,74.2
+2020-10-09 00:00:00,9.2,0.0,-0.0,0.0,3.86,76.95
+2020-10-09 01:00:00,8.92,0.0,-0.0,0.0,3.72,74.15
+2020-10-09 02:00:00,8.75,0.0,-0.0,0.0,3.66,76.85
+2020-10-09 03:00:00,8.51,0.0,-0.0,0.0,3.59,74.05
+2020-10-09 04:00:00,8.33,0.0,-0.0,0.0,3.59,76.8
+2020-10-09 05:00:00,8.19,0.0,-0.0,0.0,3.59,76.8
+2020-10-09 06:00:00,8.14,59.0,70.17,50.0,3.59,76.8
+2020-10-09 07:00:00,8.59,224.0,475.84,94.0,3.1,82.75
+2020-10-09 08:00:00,9.95,376.0,721.14,92.0,3.38,74.3
+2020-10-09 09:00:00,11.48,486.0,809.31,96.0,3.31,66.75
+2020-10-09 10:00:00,13.03,543.0,827.98,103.0,3.31,62.3
+2020-10-09 11:00:00,14.09,537.0,766.21,124.0,3.38,58.1
+2020-10-09 12:00:00,14.84,482.0,672.38,143.0,3.38,56.15
+2020-10-09 13:00:00,15.1,399.0,635.96,126.0,3.45,56.25
+2020-10-09 14:00:00,14.96,242.0,334.99,135.0,3.24,58.35
+2020-10-09 15:00:00,14.22,53.0,0.0,53.0,2.69,64.85
+2020-10-09 16:00:00,12.72,1.0,0.0,1.0,2.76,69.45
+2020-10-09 17:00:00,11.14,0.0,-0.0,0.0,2.83,74.45
+2020-10-09 18:00:00,9.91,0.0,-0.0,0.0,2.76,74.3
+2020-10-09 19:00:00,8.64,0.0,-0.0,0.0,2.76,71.35
+2020-10-09 20:00:00,7.79,0.0,-0.0,0.0,2.62,73.9
+2020-10-09 21:00:00,7.03,0.0,-0.0,0.0,2.41,76.65
+2020-10-09 22:00:00,6.3,0.0,-0.0,0.0,2.34,76.55
+2020-10-09 23:00:00,5.66,0.0,-0.0,0.0,2.28,76.5
+2020-10-10 00:00:00,5.06,0.0,-0.0,0.0,2.28,79.35
+2020-10-10 01:00:00,4.6,0.0,-0.0,0.0,2.21,79.3
+2020-10-10 02:00:00,4.04,0.0,-0.0,0.0,2.14,79.2
+2020-10-10 03:00:00,3.42,0.0,-0.0,0.0,2.07,82.25
+2020-10-10 04:00:00,2.84,0.0,-0.0,0.0,2.0,85.4
+2020-10-10 05:00:00,2.27,0.0,-0.0,0.0,2.0,88.65
+2020-10-10 06:00:00,2.06,89.0,396.31,40.0,1.86,88.65
+2020-10-10 07:00:00,4.5,241.0,633.41,71.0,1.31,85.55
+2020-10-10 08:00:00,7.72,387.0,787.05,81.0,1.38,76.7
+2020-10-10 09:00:00,9.72,487.0,824.51,94.0,1.86,66.35
+2020-10-10 10:00:00,11.19,541.0,830.87,104.0,2.34,59.6
+2020-10-10 11:00:00,12.27,548.0,823.07,109.0,2.62,55.5
+2020-10-10 12:00:00,12.87,506.0,806.62,104.0,2.69,53.6
+2020-10-10 13:00:00,13.07,427.0,805.46,86.0,2.83,53.7
+2020-10-10 14:00:00,12.77,295.0,692.32,78.0,2.83,55.65
+2020-10-10 15:00:00,12.02,145.0,516.75,54.0,2.34,62.1
+2020-10-10 16:00:00,10.53,5.0,0.0,5.0,2.28,66.55
+2020-10-10 17:00:00,8.88,0.0,-0.0,0.0,2.28,74.15
+2020-10-10 18:00:00,7.57,0.0,-0.0,0.0,2.21,79.65
+2020-10-10 19:00:00,6.52,0.0,-0.0,0.0,1.93,79.55
+2020-10-10 20:00:00,5.14,0.0,-0.0,0.0,1.79,85.6
+2020-10-10 21:00:00,4.06,0.0,-0.0,0.0,1.79,88.8
+2020-10-10 22:00:00,3.24,0.0,-0.0,0.0,1.93,88.7
+2020-10-10 23:00:00,2.67,0.0,-0.0,0.0,2.07,92.15
+2020-10-11 00:00:00,2.41,0.0,-0.0,0.0,1.66,88.65
+2020-10-11 01:00:00,2.57,0.0,-0.0,0.0,1.38,92.15
+2020-10-11 02:00:00,1.96,0.0,-0.0,0.0,1.45,92.1
+2020-10-11 03:00:00,2.58,0.0,-0.0,0.0,1.24,92.15
+2020-10-11 04:00:00,2.01,0.0,-0.0,0.0,1.45,92.1
+2020-10-11 05:00:00,1.52,0.0,-0.0,0.0,1.59,92.05
+2020-10-11 06:00:00,1.93,70.0,201.66,46.0,1.45,88.65
+2020-10-11 07:00:00,4.27,204.0,383.2,103.0,0.69,88.8
+2020-10-11 08:00:00,6.84,362.0,677.51,102.0,0.9,82.6
+2020-10-11 09:00:00,8.85,477.0,808.25,96.0,1.52,74.05
+2020-10-11 10:00:00,10.23,534.0,824.22,105.0,1.86,66.45
+2020-10-11 11:00:00,11.3,543.0,829.99,105.0,1.86,59.6
+2020-10-11 12:00:00,11.98,501.0,812.06,101.0,1.93,53.5
+2020-10-11 13:00:00,12.2,420.0,797.67,87.0,2.21,53.5
+2020-10-11 14:00:00,11.86,288.0,682.94,78.0,2.48,57.55
+2020-10-11 15:00:00,11.02,138.0,505.38,52.0,2.28,61.85
+2020-10-11 16:00:00,9.47,0.0,0.0,0.0,2.28,68.9
+2020-10-11 17:00:00,7.86,0.0,-0.0,0.0,2.07,76.8
+2020-10-11 18:00:00,6.57,0.0,-0.0,0.0,1.86,82.6
+2020-10-11 19:00:00,5.14,0.0,-0.0,0.0,1.86,88.85
+2020-10-11 20:00:00,3.98,0.0,-0.0,0.0,1.66,92.2
+2020-10-11 21:00:00,3.29,0.0,-0.0,0.0,1.45,95.7
+2020-10-11 22:00:00,3.21,0.0,-0.0,0.0,1.24,95.7
+2020-10-11 23:00:00,3.34,0.0,-0.0,0.0,1.1,95.7
+2020-10-12 00:00:00,3.61,0.0,-0.0,0.0,0.97,99.4
+2020-10-12 01:00:00,3.46,0.0,-0.0,0.0,0.9,95.7
+2020-10-12 02:00:00,2.95,0.0,-0.0,0.0,0.83,95.7
+2020-10-12 03:00:00,2.1,0.0,-0.0,0.0,0.55,99.4
+2020-10-12 04:00:00,2.32,0.0,-0.0,0.0,0.41,95.7
+2020-10-12 05:00:00,1.99,0.0,-0.0,0.0,0.76,95.65
+2020-10-12 06:00:00,2.13,40.0,26.23,37.0,0.83,99.4
+2020-10-12 07:00:00,3.25,83.0,3.87,82.0,0.28,99.4
+2020-10-12 08:00:00,3.79,96.0,0.0,96.0,0.69,99.4
+2020-10-12 09:00:00,4.88,70.0,0.0,70.0,1.17,92.25
+2020-10-12 10:00:00,5.98,86.0,0.0,86.0,1.38,88.95
+2020-10-12 11:00:00,7.24,83.0,0.0,83.0,1.52,85.75
+2020-10-12 12:00:00,8.07,70.0,0.0,70.0,1.59,79.7
+2020-10-12 13:00:00,8.68,77.0,0.0,77.0,1.66,76.85
+2020-10-12 14:00:00,8.79,140.0,39.79,128.0,1.66,76.85
+2020-10-12 15:00:00,8.57,124.0,401.76,58.0,1.66,74.05
+2020-10-12 16:00:00,7.77,0.0,0.0,0.0,1.52,79.65
+2020-10-12 17:00:00,6.39,0.0,-0.0,0.0,1.66,79.55
+2020-10-12 18:00:00,5.09,0.0,-0.0,0.0,1.59,88.85
+2020-10-12 19:00:00,3.78,0.0,-0.0,0.0,1.66,95.7
+2020-10-12 20:00:00,3.17,0.0,-0.0,0.0,1.66,95.7
+2020-10-12 21:00:00,2.54,0.0,-0.0,0.0,1.59,95.7
+2020-10-12 22:00:00,2.16,0.0,-0.0,0.0,1.59,95.65
+2020-10-12 23:00:00,1.87,0.0,-0.0,0.0,1.59,95.65
+2020-10-13 00:00:00,1.75,0.0,-0.0,0.0,1.59,95.65
+2020-10-13 01:00:00,1.88,0.0,-0.0,0.0,1.66,95.65
+2020-10-13 02:00:00,1.46,0.0,-0.0,0.0,1.59,95.65
+2020-10-13 03:00:00,1.48,0.0,-0.0,0.0,1.45,95.65
+2020-10-13 04:00:00,0.96,0.0,-0.0,0.0,1.45,99.35
+2020-10-13 05:00:00,0.69,0.0,-0.0,0.0,1.45,100.0
+2020-10-13 06:00:00,1.13,40.0,27.34,37.0,1.38,99.35
+2020-10-13 07:00:00,3.07,120.0,51.2,107.0,1.79,95.7
+2020-10-13 08:00:00,3.86,174.0,37.47,160.0,1.59,88.8
+2020-10-13 09:00:00,5.38,432.0,640.13,137.0,1.24,79.4
+2020-10-13 10:00:00,7.13,513.0,796.79,107.0,1.17,76.65
+2020-10-13 11:00:00,8.62,522.0,801.67,108.0,1.45,71.35
+2020-10-13 12:00:00,9.57,488.0,817.02,95.0,1.86,66.35
+2020-10-13 13:00:00,10.09,404.0,791.17,83.0,2.14,64.0
+2020-10-13 14:00:00,10.09,273.0,669.6,75.0,2.34,64.0
+2020-10-13 15:00:00,9.57,123.0,448.16,52.0,1.93,66.35
+2020-10-13 16:00:00,8.3,0.0,0.0,0.0,1.86,73.95
+2020-10-13 17:00:00,6.83,0.0,-0.0,0.0,1.93,79.55
+2020-10-13 18:00:00,5.57,0.0,-0.0,0.0,1.93,85.65
+2020-10-13 19:00:00,4.25,0.0,-0.0,0.0,1.72,92.2
+2020-10-13 20:00:00,3.14,0.0,-0.0,0.0,1.66,95.7
+2020-10-13 21:00:00,2.18,0.0,-0.0,0.0,1.66,95.65
+2020-10-13 22:00:00,1.44,0.0,-0.0,0.0,1.72,95.65
+2020-10-13 23:00:00,0.84,0.0,-0.0,0.0,1.72,99.35
+2020-10-14 00:00:00,0.33,0.0,-0.0,0.0,1.66,99.4
+2020-10-14 01:00:00,-0.02,0.0,-0.0,0.0,1.66,99.4
+2020-10-14 02:00:00,-0.35,0.0,-0.0,0.0,1.66,99.4
+2020-10-14 03:00:00,-0.63,0.0,-0.0,0.0,1.66,99.4
+2020-10-14 04:00:00,-0.88,0.0,-0.0,0.0,1.45,99.4
+2020-10-14 05:00:00,-0.94,0.0,-0.0,0.0,1.52,99.4
+2020-10-14 06:00:00,-0.65,39.0,28.55,36.0,1.38,99.4
+2020-10-14 07:00:00,1.65,101.0,24.09,95.0,1.45,95.65
+2020-10-14 08:00:00,3.19,149.0,16.28,143.0,1.66,99.4
+2020-10-14 09:00:00,4.46,82.0,0.0,82.0,2.28,92.25
+2020-10-14 10:00:00,5.42,97.0,0.0,97.0,2.41,88.9
+2020-10-14 11:00:00,6.3,72.0,0.0,72.0,2.62,85.7
+2020-10-14 12:00:00,6.87,152.0,0.0,152.0,2.83,82.6
+2020-10-14 13:00:00,7.23,191.0,40.01,175.0,2.97,82.6
+2020-10-14 14:00:00,7.27,243.0,500.25,98.0,2.97,82.6
+2020-10-14 15:00:00,7.06,56.0,19.66,53.0,2.69,82.6
+2020-10-14 16:00:00,6.48,0.0,-0.0,0.0,2.41,82.6
+2020-10-14 17:00:00,6.2,0.0,-0.0,0.0,2.48,88.95
+2020-10-14 18:00:00,6.45,0.0,-0.0,0.0,2.62,85.75
+2020-10-14 19:00:00,7.03,0.0,-0.0,0.0,2.62,89.0
+2020-10-14 20:00:00,7.3,0.0,-0.0,0.0,2.62,92.35
+2020-10-14 21:00:00,7.39,0.0,-0.0,0.0,2.55,89.0
+2020-10-14 22:00:00,7.41,0.0,-0.0,0.0,2.62,92.35
+2020-10-14 23:00:00,7.41,0.0,-0.0,0.0,2.62,92.35
+2020-10-15 00:00:00,7.39,0.0,-0.0,0.0,2.62,92.35
+2020-10-15 01:00:00,7.98,0.0,-0.0,0.0,2.55,95.8
+2020-10-15 02:00:00,7.95,0.0,-0.0,0.0,2.69,95.8
+2020-10-15 03:00:00,7.85,0.0,-0.0,0.0,2.69,99.4
+2020-10-15 04:00:00,7.78,0.0,-0.0,0.0,2.69,100.0
+2020-10-15 05:00:00,7.81,0.0,-0.0,0.0,2.62,100.0
+2020-10-15 06:00:00,7.75,34.0,19.92,32.0,2.48,100.0
+2020-10-15 07:00:00,8.06,77.0,4.1,76.0,2.28,99.4
+2020-10-15 08:00:00,8.37,94.0,0.0,94.0,2.83,92.4
+2020-10-15 09:00:00,8.41,80.0,0.0,80.0,2.62,92.4
+2020-10-15 10:00:00,9.07,98.0,0.0,98.0,2.55,85.95
+2020-10-15 11:00:00,9.31,100.0,0.0,100.0,2.28,85.95
+2020-10-15 12:00:00,9.54,163.0,4.26,161.0,2.48,82.9
+2020-10-15 13:00:00,9.71,112.0,0.0,112.0,2.55,79.9
+2020-10-15 14:00:00,9.69,59.0,0.0,59.0,2.41,79.9
+2020-10-15 15:00:00,9.49,36.0,0.0,36.0,1.52,79.9
+2020-10-15 16:00:00,9.0,0.0,-0.0,0.0,1.03,82.85
+2020-10-15 17:00:00,8.2,0.0,-0.0,0.0,1.24,89.05
+2020-10-15 18:00:00,7.28,0.0,-0.0,0.0,1.52,95.8
+2020-10-15 19:00:00,6.33,0.0,-0.0,0.0,1.31,95.8
+2020-10-15 20:00:00,5.67,0.0,-0.0,0.0,1.45,95.75
+2020-10-15 21:00:00,5.29,0.0,-0.0,0.0,1.52,95.75
+2020-10-15 22:00:00,5.14,0.0,-0.0,0.0,1.59,95.75
+2020-10-15 23:00:00,4.75,0.0,-0.0,0.0,1.72,95.75
+2020-10-16 00:00:00,4.78,0.0,-0.0,0.0,1.72,95.75
+2020-10-16 01:00:00,4.61,0.0,-0.0,0.0,1.79,95.75
+2020-10-16 02:00:00,4.77,0.0,-0.0,0.0,1.72,95.75
+2020-10-16 03:00:00,4.72,0.0,-0.0,0.0,1.66,95.75
+2020-10-16 04:00:00,4.88,0.0,-0.0,0.0,1.45,95.75
+2020-10-16 05:00:00,5.53,0.0,-0.0,0.0,1.31,95.75
+2020-10-16 06:00:00,5.96,57.0,240.22,34.0,1.24,95.8
+2020-10-16 07:00:00,6.28,121.0,79.4,102.0,1.17,95.8
+2020-10-16 08:00:00,7.73,190.0,78.12,162.0,1.1,95.8
+2020-10-16 09:00:00,8.7,317.0,249.45,206.0,1.03,89.1
+2020-10-16 10:00:00,9.52,349.0,231.18,235.0,1.03,82.9
+2020-10-16 11:00:00,9.95,326.0,166.15,243.0,0.69,79.95
+2020-10-16 12:00:00,10.34,150.0,2.16,149.0,0.48,82.95
+2020-10-16 13:00:00,10.31,229.0,118.46,183.0,1.03,86.0
+2020-10-16 14:00:00,10.26,127.0,43.12,115.0,1.38,89.2
+2020-10-16 15:00:00,9.77,56.0,35.42,51.0,1.31,92.45
+2020-10-16 16:00:00,8.89,0.0,-0.0,0.0,1.45,89.1
+2020-10-16 17:00:00,8.22,0.0,-0.0,0.0,1.45,95.8
+2020-10-16 18:00:00,7.87,0.0,-0.0,0.0,1.52,92.4
+2020-10-16 19:00:00,7.42,0.0,-0.0,0.0,1.72,95.8
+2020-10-16 20:00:00,6.78,0.0,-0.0,0.0,1.72,95.8
+2020-10-16 21:00:00,6.27,0.0,-0.0,0.0,1.72,95.8
+2020-10-16 22:00:00,5.95,0.0,-0.0,0.0,1.72,92.3
+2020-10-16 23:00:00,5.5,0.0,-0.0,0.0,1.79,92.3
+2020-10-17 00:00:00,4.84,0.0,-0.0,0.0,1.93,92.25
+2020-10-17 01:00:00,4.34,0.0,-0.0,0.0,2.0,92.25
+2020-10-17 02:00:00,4.04,0.0,-0.0,0.0,2.07,95.75
+2020-10-17 03:00:00,3.32,0.0,-0.0,0.0,2.07,92.15
+2020-10-17 04:00:00,2.76,0.0,-0.0,0.0,2.0,95.7
+2020-10-17 05:00:00,2.22,0.0,-0.0,0.0,2.0,95.65
+2020-10-17 06:00:00,2.08,48.0,164.7,33.0,2.0,95.65
+2020-10-17 07:00:00,3.29,181.0,405.27,86.0,2.0,95.7
+2020-10-17 08:00:00,4.6,329.0,684.94,87.0,2.97,85.55
+2020-10-17 09:00:00,5.72,430.0,757.34,97.0,2.97,82.5
+2020-10-17 10:00:00,6.65,481.0,762.83,109.0,3.03,76.65
+2020-10-17 11:00:00,7.49,489.0,767.32,110.0,3.38,71.15
+2020-10-17 12:00:00,7.93,450.0,759.67,102.0,3.45,63.6
+2020-10-17 13:00:00,8.16,370.0,739.71,87.0,3.45,61.2
+2020-10-17 14:00:00,7.95,242.0,620.08,73.0,3.17,58.9
+2020-10-17 15:00:00,7.33,101.0,420.7,44.0,2.62,63.35
+2020-10-17 16:00:00,6.03,0.0,-0.0,0.0,2.62,63.25
+2020-10-17 17:00:00,4.93,0.0,-0.0,0.0,2.48,65.55
+2020-10-17 18:00:00,4.03,0.0,-0.0,0.0,2.34,70.6
+2020-10-17 19:00:00,3.45,0.0,-0.0,0.0,2.28,70.5
+2020-10-17 20:00:00,2.47,0.0,-0.0,0.0,2.0,76.0
+2020-10-17 21:00:00,1.45,0.0,-0.0,0.0,1.93,78.9
+2020-10-17 22:00:00,0.5,0.0,-0.0,0.0,1.72,81.9
+2020-10-17 23:00:00,0.18,0.0,-0.0,0.0,1.52,81.8
+2020-10-18 00:00:00,0.56,0.0,-0.0,0.0,1.17,78.75
+2020-10-18 01:00:00,0.87,0.0,-0.0,0.0,0.97,75.75
+2020-10-18 02:00:00,1.07,0.0,-0.0,0.0,0.69,75.75
+2020-10-18 03:00:00,0.78,0.0,-0.0,0.0,0.48,78.75
+2020-10-18 04:00:00,0.61,0.0,-0.0,0.0,0.34,81.9
+2020-10-18 05:00:00,0.44,0.0,-0.0,0.0,0.48,78.75
+2020-10-18 06:00:00,0.35,59.0,381.94,26.0,0.55,78.75
+2020-10-18 07:00:00,0.99,197.0,579.45,64.0,0.0,88.55
+2020-10-18 08:00:00,2.68,329.0,703.57,84.0,0.55,82.15
+2020-10-18 09:00:00,4.32,426.0,755.06,98.0,0.97,76.3
+2020-10-18 10:00:00,5.6,480.0,771.47,108.0,1.24,73.65
+2020-10-18 11:00:00,6.67,495.0,810.91,99.0,1.24,71.05
+2020-10-18 12:00:00,7.39,453.0,789.1,96.0,0.97,71.15
+2020-10-18 13:00:00,7.78,367.0,748.26,85.0,0.76,71.15
+2020-10-18 14:00:00,7.85,232.0,569.58,80.0,0.55,71.15
+2020-10-18 15:00:00,7.54,95.0,400.36,43.0,0.76,71.15
+2020-10-18 16:00:00,6.32,0.0,-0.0,0.0,1.38,76.55
+2020-10-18 17:00:00,4.84,0.0,-0.0,0.0,0.76,82.4
+2020-10-18 18:00:00,4.41,0.0,-0.0,0.0,0.9,82.35
+2020-10-18 19:00:00,1.78,0.0,-0.0,0.0,1.79,95.65
+2020-10-18 20:00:00,0.53,0.0,-0.0,0.0,2.0,99.4
+2020-10-18 21:00:00,-0.03,0.0,-0.0,0.0,2.0,99.4
+2020-10-18 22:00:00,-0.15,0.0,-0.0,0.0,2.14,95.6
+2020-10-18 23:00:00,-0.02,0.0,-0.0,0.0,2.21,95.6
+2020-10-19 00:00:00,-0.01,0.0,-0.0,0.0,2.21,95.6
+2020-10-19 01:00:00,0.02,0.0,-0.0,0.0,2.21,95.6
+2020-10-19 02:00:00,0.09,0.0,-0.0,0.0,2.34,92.0
+2020-10-19 03:00:00,0.45,0.0,-0.0,0.0,2.55,92.0
+2020-10-19 04:00:00,0.76,0.0,-0.0,0.0,2.62,95.65
+2020-10-19 05:00:00,1.12,0.0,-0.0,0.0,2.69,92.05
+2020-10-19 06:00:00,2.05,13.0,0.0,13.0,2.97,88.65
+2020-10-19 07:00:00,3.66,28.0,0.0,28.0,3.17,82.25
+2020-10-19 08:00:00,4.97,94.0,0.0,94.0,3.17,76.4
+2020-10-19 09:00:00,6.3,241.0,88.55,203.0,3.38,76.55
+2020-10-19 10:00:00,7.03,142.0,0.0,142.0,3.52,73.8
+2020-10-19 11:00:00,7.5,230.0,35.21,213.0,3.45,76.7
+2020-10-19 12:00:00,7.74,141.0,0.0,141.0,3.52,79.65
+2020-10-19 13:00:00,8.17,71.0,0.0,71.0,2.9,79.7
+2020-10-19 14:00:00,7.97,20.0,0.0,20.0,3.31,76.8
+2020-10-19 15:00:00,7.56,42.0,16.09,40.0,3.17,76.7
+2020-10-19 16:00:00,6.91,0.0,-0.0,0.0,3.03,79.55
+2020-10-19 17:00:00,6.39,0.0,-0.0,0.0,3.17,79.55
+2020-10-19 18:00:00,5.82,0.0,-0.0,0.0,3.17,88.9
+2020-10-19 19:00:00,5.79,0.0,-0.0,0.0,2.76,88.9
+2020-10-19 20:00:00,5.7,0.0,-0.0,0.0,2.69,92.3
+2020-10-19 21:00:00,5.66,0.0,-0.0,0.0,2.48,92.3
+2020-10-19 22:00:00,5.55,0.0,-0.0,0.0,2.48,92.3
+2020-10-19 23:00:00,5.36,0.0,-0.0,0.0,2.69,88.9
+2020-10-20 00:00:00,4.96,0.0,-0.0,0.0,2.76,92.25
+2020-10-20 01:00:00,4.8,0.0,-0.0,0.0,2.9,92.25
+2020-10-20 02:00:00,4.7,0.0,-0.0,0.0,3.03,92.25
+2020-10-20 03:00:00,4.41,0.0,-0.0,0.0,3.03,88.85
+2020-10-20 04:00:00,4.23,0.0,-0.0,0.0,3.1,92.2
+2020-10-20 05:00:00,4.26,0.0,-0.0,0.0,3.17,92.2
+2020-10-20 06:00:00,4.8,30.0,51.91,26.0,3.31,92.25
+2020-10-20 07:00:00,5.21,19.0,0.0,19.0,3.31,88.85
+2020-10-20 08:00:00,5.99,234.0,236.66,154.0,3.03,85.7
+2020-10-20 09:00:00,6.67,92.0,0.0,92.0,4.55,85.75
+2020-10-20 10:00:00,7.41,283.0,112.45,230.0,3.79,85.8
+2020-10-20 11:00:00,7.74,342.0,236.79,229.0,3.45,89.0
+2020-10-20 12:00:00,7.85,79.0,0.0,79.0,3.93,89.0
+2020-10-20 13:00:00,6.81,78.0,0.0,78.0,4.41,89.0
+2020-10-20 14:00:00,6.44,137.0,93.88,113.0,4.34,85.75
+2020-10-20 15:00:00,5.94,21.0,0.0,21.0,3.66,88.95
+2020-10-20 16:00:00,5.6,0.0,-0.0,0.0,3.38,88.9
+2020-10-20 17:00:00,5.33,0.0,-0.0,0.0,3.79,85.65
+2020-10-20 18:00:00,4.89,0.0,-0.0,0.0,4.14,85.6
+2020-10-20 19:00:00,4.74,0.0,-0.0,0.0,4.14,88.85
+2020-10-20 20:00:00,4.42,0.0,-0.0,0.0,4.62,85.55
+2020-10-20 21:00:00,4.1,0.0,-0.0,0.0,4.83,85.5
+2020-10-20 22:00:00,3.77,0.0,-0.0,0.0,5.17,85.45
+2020-10-20 23:00:00,3.38,0.0,-0.0,0.0,5.59,82.25
+2020-10-21 00:00:00,3.21,0.0,-0.0,0.0,5.93,85.4
+2020-10-21 01:00:00,3.14,0.0,-0.0,0.0,5.86,85.4
+2020-10-21 02:00:00,3.16,0.0,-0.0,0.0,5.72,85.4
+2020-10-21 03:00:00,3.01,0.0,-0.0,0.0,5.59,85.4
+2020-10-21 04:00:00,2.88,0.0,-0.0,0.0,5.66,85.4
+2020-10-21 05:00:00,2.68,0.0,-0.0,0.0,5.45,85.35
+2020-10-21 06:00:00,2.51,37.0,165.8,25.0,4.83,85.35
+2020-10-21 07:00:00,2.7,122.0,125.66,95.0,5.52,88.65
+2020-10-21 08:00:00,3.35,292.0,549.64,109.0,6.69,82.25
+2020-10-21 09:00:00,3.99,323.0,322.53,188.0,6.48,76.25
+2020-10-21 10:00:00,5.08,202.0,19.32,193.0,6.62,65.55
+2020-10-21 11:00:00,6.3,225.0,33.92,209.0,6.97,56.3
+2020-10-21 12:00:00,7.04,355.0,390.3,185.0,6.41,54.3
+2020-10-21 13:00:00,7.17,133.0,8.33,130.0,5.86,56.45
+2020-10-21 14:00:00,6.48,218.0,579.74,73.0,4.9,63.35
+2020-10-21 15:00:00,6.3,41.0,26.45,38.0,5.1,63.25
+2020-10-21 16:00:00,6.2,0.0,-0.0,0.0,4.97,60.85
+2020-10-21 17:00:00,5.96,0.0,-0.0,0.0,4.83,58.55
+2020-10-21 18:00:00,5.77,0.0,-0.0,0.0,4.62,58.45
+2020-10-21 19:00:00,5.2,0.0,-0.0,0.0,4.41,65.55
+2020-10-21 20:00:00,4.75,0.0,-0.0,0.0,4.48,68.0
+2020-10-21 21:00:00,4.47,0.0,-0.0,0.0,4.55,65.4
+2020-10-21 22:00:00,4.32,0.0,-0.0,0.0,4.62,65.4
+2020-10-21 23:00:00,4.1,0.0,-0.0,0.0,4.55,67.9
+2020-10-22 00:00:00,3.9,0.0,-0.0,0.0,4.34,67.9
+2020-10-22 01:00:00,3.43,0.0,-0.0,0.0,4.21,67.8
+2020-10-22 02:00:00,3.21,0.0,-0.0,0.0,4.21,67.7
+2020-10-22 03:00:00,2.98,0.0,-0.0,0.0,4.28,67.7
+2020-10-22 04:00:00,2.82,0.0,-0.0,0.0,4.41,67.7
+2020-10-22 05:00:00,2.72,0.0,-0.0,0.0,4.48,67.6
+2020-10-22 06:00:00,2.68,31.0,118.17,23.0,4.48,67.6
+2020-10-22 07:00:00,3.42,140.0,242.88,89.0,4.41,67.8
+2020-10-22 08:00:00,4.76,262.0,402.61,130.0,3.72,68.0
+2020-10-22 09:00:00,6.1,376.0,590.37,132.0,4.34,58.55
+2020-10-22 10:00:00,7.18,310.0,184.59,225.0,4.41,58.65
+2020-10-22 11:00:00,8.19,334.0,235.96,224.0,4.41,58.9
+2020-10-22 12:00:00,8.9,310.0,248.83,203.0,4.21,56.9
+2020-10-22 13:00:00,9.14,205.0,107.21,167.0,3.86,59.15
+2020-10-22 14:00:00,8.89,115.0,49.05,103.0,3.1,59.15
+2020-10-22 15:00:00,8.41,39.0,27.77,36.0,2.62,61.3
+2020-10-22 16:00:00,7.55,0.0,-0.0,0.0,2.62,63.5
+2020-10-22 17:00:00,6.91,0.0,-0.0,0.0,2.55,65.85
+2020-10-22 18:00:00,6.2,0.0,-0.0,0.0,2.41,68.3
+2020-10-22 19:00:00,5.7,0.0,-0.0,0.0,2.21,65.65
+2020-10-22 20:00:00,5.05,0.0,-0.0,0.0,2.14,68.1
+2020-10-22 21:00:00,4.29,0.0,-0.0,0.0,2.14,73.4
+2020-10-22 22:00:00,3.33,0.0,-0.0,0.0,2.21,73.3
+2020-10-22 23:00:00,2.37,0.0,-0.0,0.0,2.07,79.0
+2020-10-23 00:00:00,1.42,0.0,-0.0,0.0,2.07,85.25
+2020-10-23 01:00:00,0.6,0.0,-0.0,0.0,2.07,88.5
+2020-10-23 02:00:00,0.07,0.0,-0.0,0.0,2.14,88.45
+2020-10-23 03:00:00,-0.23,0.0,-0.0,0.0,2.21,91.95
+2020-10-23 04:00:00,-0.41,0.0,-0.0,0.0,2.28,88.45
+2020-10-23 05:00:00,-0.35,0.0,-0.0,0.0,2.41,88.45
+2020-10-23 06:00:00,-0.35,34.0,206.24,21.0,2.34,88.45
+2020-10-23 07:00:00,0.94,166.0,487.56,66.0,2.28,88.55
+2020-10-23 08:00:00,3.77,299.0,672.28,82.0,2.41,82.25
+2020-10-23 09:00:00,6.1,382.0,656.79,114.0,3.03,70.95
+2020-10-23 10:00:00,7.77,435.0,685.58,123.0,3.24,71.15
+2020-10-23 11:00:00,9.04,442.0,688.09,125.0,3.38,66.25
+2020-10-23 12:00:00,10.0,415.0,749.12,97.0,3.79,64.0
+2020-10-23 13:00:00,10.85,316.0,607.53,104.0,4.0,61.75
+2020-10-23 14:00:00,11.39,188.0,413.86,89.0,3.79,61.85
+2020-10-23 15:00:00,10.85,50.0,97.32,40.0,3.45,64.1
+2020-10-23 16:00:00,9.78,0.0,-0.0,0.0,3.59,68.9
+2020-10-23 17:00:00,8.98,0.0,-0.0,0.0,3.66,71.4
+2020-10-23 18:00:00,8.4,0.0,-0.0,0.0,3.79,76.85
+2020-10-23 19:00:00,8.01,0.0,-0.0,0.0,4.0,82.7
+2020-10-23 20:00:00,7.89,0.0,-0.0,0.0,4.0,85.85
+2020-10-23 21:00:00,8.33,0.0,-0.0,0.0,4.0,85.85
+2020-10-23 22:00:00,8.55,0.0,-0.0,0.0,3.93,82.75
+2020-10-23 23:00:00,8.41,0.0,-0.0,0.0,3.86,79.75
+2020-10-24 00:00:00,8.4,0.0,-0.0,0.0,3.93,79.75
+2020-10-24 01:00:00,8.82,0.0,-0.0,0.0,4.0,79.75
+2020-10-24 02:00:00,8.69,0.0,-0.0,0.0,4.0,79.75
+2020-10-24 03:00:00,8.86,0.0,-0.0,0.0,3.86,82.75
+2020-10-24 04:00:00,9.02,0.0,-0.0,0.0,3.86,82.85
+2020-10-24 05:00:00,8.99,0.0,-0.0,0.0,3.86,82.85
+2020-10-24 06:00:00,8.67,25.0,85.66,20.0,3.93,82.75
+2020-10-24 07:00:00,8.4,172.0,589.33,54.0,4.21,76.85
+2020-10-24 08:00:00,9.01,191.0,138.49,147.0,3.66,76.95
+2020-10-24 09:00:00,9.85,127.0,2.48,126.0,6.62,68.9
+2020-10-24 10:00:00,10.26,189.0,17.79,181.0,5.17,69.0
+2020-10-24 11:00:00,10.74,113.0,0.0,113.0,5.45,64.1
+2020-10-24 12:00:00,11.13,254.0,124.1,202.0,5.52,59.6
+2020-10-24 13:00:00,11.15,304.0,576.41,106.0,5.1,57.4
+2020-10-24 14:00:00,10.67,125.0,94.08,103.0,4.62,57.3
+2020-10-24 15:00:00,9.84,69.0,389.67,31.0,4.28,61.55
+2020-10-24 16:00:00,8.97,0.0,-0.0,0.0,4.0,61.45
+2020-10-24 17:00:00,8.16,0.0,-0.0,0.0,3.79,63.6
+2020-10-24 18:00:00,7.31,0.0,-0.0,0.0,3.72,68.4
+2020-10-24 19:00:00,6.76,0.0,-0.0,0.0,3.24,71.05
+2020-10-24 20:00:00,6.13,0.0,-0.0,0.0,3.31,73.7
+2020-10-24 21:00:00,5.86,0.0,-0.0,0.0,3.24,73.7
+2020-10-24 22:00:00,5.37,0.0,-0.0,0.0,3.03,76.5
+2020-10-24 23:00:00,4.83,0.0,-0.0,0.0,2.9,79.35
+2020-10-25 00:00:00,4.59,0.0,-0.0,0.0,2.83,82.35
+2020-10-25 01:00:00,4.38,0.0,-0.0,0.0,2.62,82.35
+2020-10-25 02:00:00,4.0,0.0,-0.0,0.0,2.55,85.5
+2020-10-25 03:00:00,3.62,0.0,-0.0,0.0,2.41,88.75
+2020-10-25 04:00:00,3.38,0.0,-0.0,0.0,2.28,88.75
+2020-10-25 05:00:00,3.1,0.0,-0.0,0.0,2.07,92.15
+2020-10-25 06:00:00,2.91,15.0,18.62,14.0,1.93,88.7
+2020-10-25 07:00:00,3.98,88.0,46.07,79.0,2.14,92.2
+2020-10-25 08:00:00,4.81,194.0,150.33,147.0,3.31,88.85
+2020-10-25 09:00:00,5.45,106.0,0.0,106.0,3.45,79.4
+2020-10-25 10:00:00,5.94,215.0,38.26,198.0,3.59,76.55
+2020-10-25 11:00:00,6.41,211.0,31.12,197.0,3.45,71.05
+2020-10-25 12:00:00,6.36,212.0,53.19,190.0,3.72,71.05
+2020-10-25 13:00:00,6.58,182.0,76.9,156.0,3.86,71.05
+2020-10-25 14:00:00,6.59,147.0,196.9,102.0,3.24,68.4
+2020-10-25 15:00:00,6.44,45.0,97.45,36.0,2.83,68.4
+2020-10-25 16:00:00,5.96,0.0,-0.0,0.0,2.55,68.3
+2020-10-25 17:00:00,5.36,0.0,-0.0,0.0,2.41,70.85
+2020-10-25 18:00:00,4.67,0.0,-0.0,0.0,2.34,76.3
+2020-10-25 19:00:00,4.17,0.0,-0.0,0.0,2.14,82.3
+2020-10-25 20:00:00,3.63,0.0,-0.0,0.0,2.48,82.25
+2020-10-25 21:00:00,3.27,0.0,-0.0,0.0,2.69,88.7
+2020-10-25 22:00:00,3.08,0.0,-0.0,0.0,2.83,88.7
+2020-10-25 23:00:00,3.02,0.0,-0.0,0.0,3.03,88.7
+2020-10-26 00:00:00,3.28,0.0,-0.0,0.0,3.38,88.7
+2020-10-26 01:00:00,3.4,0.0,-0.0,0.0,3.72,85.45
+2020-10-26 02:00:00,3.48,0.0,-0.0,0.0,3.79,85.45
+2020-10-26 03:00:00,3.65,0.0,-0.0,0.0,3.72,85.45
+2020-10-26 04:00:00,3.25,0.0,-0.0,0.0,3.52,88.7
+2020-10-26 05:00:00,3.15,0.0,-0.0,0.0,3.31,88.7
+2020-10-26 06:00:00,3.3,22.0,122.3,16.0,3.17,88.7
+2020-10-26 07:00:00,3.7,116.0,178.48,82.0,2.9,88.75
+2020-10-26 08:00:00,4.5,132.0,26.01,124.0,3.03,85.55
+2020-10-26 09:00:00,5.15,125.0,2.55,124.0,4.28,82.4
+2020-10-26 10:00:00,5.78,227.0,54.66,203.0,4.34,79.4
+2020-10-26 11:00:00,6.16,102.0,0.0,102.0,4.14,73.7
+2020-10-26 12:00:00,6.59,57.0,0.0,57.0,3.86,68.4
+2020-10-26 13:00:00,6.89,223.0,198.33,157.0,3.79,68.4
+2020-10-26 14:00:00,6.76,163.0,322.42,91.0,3.59,65.85
+2020-10-26 15:00:00,6.26,61.0,378.14,28.0,2.41,68.3
+2020-10-26 16:00:00,5.14,0.0,-0.0,0.0,1.79,73.55
+2020-10-26 17:00:00,3.62,0.0,-0.0,0.0,1.72,82.25
+2020-10-26 18:00:00,2.08,0.0,-0.0,0.0,1.72,88.65
+2020-10-26 19:00:00,1.96,0.0,-0.0,0.0,1.66,92.1
+2020-10-26 20:00:00,1.51,0.0,-0.0,0.0,1.59,95.65
+2020-10-26 21:00:00,1.16,0.0,-0.0,0.0,1.59,99.35
+2020-10-26 22:00:00,0.53,0.0,-0.0,0.0,1.66,99.4
+2020-10-26 23:00:00,-0.43,0.0,-0.0,0.0,1.72,99.4
+2020-10-27 00:00:00,-1.05,0.0,-0.0,0.0,1.79,99.4
+2020-10-27 01:00:00,-1.56,0.0,-0.0,0.0,1.79,99.4
+2020-10-27 02:00:00,-1.55,0.0,-0.0,0.0,1.79,99.4
+2020-10-27 03:00:00,-1.41,0.0,-0.0,0.0,1.93,99.4
+2020-10-27 04:00:00,-0.9,0.0,-0.0,0.0,1.93,99.4
+2020-10-27 05:00:00,-0.54,0.0,-0.0,0.0,2.0,99.4
+2020-10-27 06:00:00,-0.15,19.0,112.56,14.0,2.21,99.4
+2020-10-27 07:00:00,1.0,147.0,484.78,57.0,2.41,99.35
+2020-10-27 08:00:00,2.48,267.0,591.61,88.0,2.28,92.15
+2020-10-27 09:00:00,4.47,353.0,619.85,113.0,2.41,85.55
+2020-10-27 10:00:00,6.37,401.0,627.07,129.0,2.97,76.65
+2020-10-27 11:00:00,7.4,405.0,619.44,133.0,2.97,76.7
+2020-10-27 12:00:00,8.25,371.0,630.49,117.0,3.03,73.95
+2020-10-27 13:00:00,8.68,243.0,308.4,142.0,2.97,68.7
+2020-10-27 14:00:00,8.57,110.0,77.93,93.0,2.83,68.7
+2020-10-27 15:00:00,7.9,33.0,48.63,29.0,2.48,71.25
+2020-10-27 16:00:00,6.87,0.0,-0.0,0.0,2.55,76.65
+2020-10-27 17:00:00,6.34,0.0,-0.0,0.0,2.62,76.55
+2020-10-27 18:00:00,6.23,0.0,-0.0,0.0,2.55,76.55
+2020-10-27 19:00:00,6.41,0.0,-0.0,0.0,2.55,73.8
+2020-10-27 20:00:00,6.33,0.0,-0.0,0.0,2.69,73.7
+2020-10-27 21:00:00,6.63,0.0,-0.0,0.0,2.76,71.05
+2020-10-27 22:00:00,6.62,0.0,-0.0,0.0,2.76,68.4
+2020-10-27 23:00:00,7.0,0.0,-0.0,0.0,2.83,68.4
+2020-10-28 00:00:00,7.11,0.0,-0.0,0.0,2.69,68.4
+2020-10-28 01:00:00,7.05,0.0,-0.0,0.0,2.62,68.4
+2020-10-28 02:00:00,7.02,0.0,-0.0,0.0,2.55,65.85
+2020-10-28 03:00:00,7.04,0.0,-0.0,0.0,2.55,65.85
+2020-10-28 04:00:00,7.03,0.0,-0.0,0.0,2.48,65.85
+2020-10-28 05:00:00,7.03,0.0,-0.0,0.0,2.55,65.85
+2020-10-28 06:00:00,7.09,10.0,0.0,10.0,2.62,65.85
+2020-10-28 07:00:00,7.16,62.0,11.06,60.0,2.83,73.8
+2020-10-28 08:00:00,8.11,179.0,144.52,136.0,2.76,71.25
+2020-10-28 09:00:00,9.07,73.0,0.0,73.0,2.9,66.25
+2020-10-28 10:00:00,10.24,360.0,455.07,165.0,2.97,61.65
+2020-10-28 11:00:00,11.15,163.0,6.92,160.0,2.97,55.3
+2020-10-28 12:00:00,11.59,395.0,794.83,79.0,2.83,53.35
+2020-10-28 13:00:00,11.89,248.0,363.05,131.0,2.9,55.4
+2020-10-28 14:00:00,11.86,164.0,413.07,76.0,2.76,57.55
+2020-10-28 15:00:00,11.19,31.0,64.67,26.0,2.69,59.6
+2020-10-28 16:00:00,9.83,0.0,-0.0,0.0,2.55,63.9
+2020-10-28 17:00:00,8.85,0.0,-0.0,0.0,2.69,66.15
+2020-10-28 18:00:00,8.21,0.0,-0.0,0.0,2.69,68.6
+2020-10-28 19:00:00,8.08,0.0,-0.0,0.0,2.55,68.6
+2020-10-28 20:00:00,7.42,0.0,-0.0,0.0,2.62,68.5
+2020-10-28 21:00:00,6.67,0.0,-0.0,0.0,2.62,71.05
+2020-10-28 22:00:00,6.24,0.0,-0.0,0.0,2.48,73.7
+2020-10-28 23:00:00,5.52,0.0,-0.0,0.0,2.48,76.5
+2020-10-29 00:00:00,4.83,0.0,-0.0,0.0,2.28,79.35
+2020-10-29 01:00:00,4.03,0.0,-0.0,0.0,2.14,85.5
+2020-10-29 02:00:00,3.19,0.0,-0.0,0.0,2.07,88.7
+2020-10-29 03:00:00,2.36,0.0,-0.0,0.0,2.0,88.65
+2020-10-29 04:00:00,1.76,0.0,-0.0,0.0,2.0,95.65
+2020-10-29 05:00:00,1.44,0.0,-0.0,0.0,2.07,95.65
+2020-10-29 06:00:00,1.24,10.0,0.0,10.0,2.14,99.35
+2020-10-29 07:00:00,2.6,142.0,511.38,52.0,2.21,92.15
+2020-10-29 08:00:00,5.87,257.0,594.78,83.0,2.07,82.55
+2020-10-29 09:00:00,8.79,346.0,636.79,106.0,2.28,76.85
+2020-10-29 10:00:00,10.55,395.0,654.42,118.0,2.83,69.1
+2020-10-29 11:00:00,11.78,369.0,492.37,158.0,3.03,64.35
+2020-10-29 12:00:00,12.5,348.0,560.75,128.0,3.03,59.95
+2020-10-29 13:00:00,12.72,273.0,532.94,104.0,2.97,59.95
+2020-10-29 14:00:00,12.3,148.0,307.68,84.0,2.76,64.45
+2020-10-29 15:00:00,10.95,35.0,110.41,27.0,3.03,69.15
+2020-10-29 16:00:00,9.41,0.0,-0.0,0.0,3.38,74.2
+2020-10-29 17:00:00,8.67,0.0,-0.0,0.0,3.52,76.85
+2020-10-29 18:00:00,8.29,0.0,-0.0,0.0,3.66,79.7
+2020-10-29 19:00:00,8.03,0.0,-0.0,0.0,3.93,71.25
+2020-10-29 20:00:00,7.66,0.0,-0.0,0.0,4.21,73.9
+2020-10-29 21:00:00,7.18,0.0,-0.0,0.0,4.41,76.65
+2020-10-29 22:00:00,6.63,0.0,-0.0,0.0,4.48,73.8
+2020-10-29 23:00:00,6.1,0.0,-0.0,0.0,4.48,76.55
+2020-10-30 00:00:00,5.63,0.0,-0.0,0.0,4.55,79.4
+2020-10-30 01:00:00,5.36,0.0,-0.0,0.0,4.62,76.5
+2020-10-30 02:00:00,5.06,0.0,-0.0,0.0,4.69,79.35
+2020-10-30 03:00:00,4.82,0.0,-0.0,0.0,4.76,79.3
+2020-10-30 04:00:00,4.58,0.0,-0.0,0.0,4.76,76.3
+2020-10-30 05:00:00,4.34,0.0,-0.0,0.0,4.83,76.3
+2020-10-30 06:00:00,4.12,7.0,0.0,7.0,4.83,76.25
+2020-10-30 07:00:00,4.21,121.0,327.12,65.0,4.55,79.2
+2020-10-30 08:00:00,5.42,251.0,573.78,86.0,4.34,73.65
+2020-10-30 09:00:00,7.17,330.0,562.17,121.0,4.41,73.8
+2020-10-30 10:00:00,8.95,375.0,566.88,138.0,4.28,68.8
+2020-10-30 11:00:00,10.45,386.0,592.93,135.0,4.07,66.55
+2020-10-30 12:00:00,11.54,360.0,650.92,108.0,3.79,64.35
+2020-10-30 13:00:00,12.08,281.0,621.77,87.0,3.52,64.45
+2020-10-30 14:00:00,11.82,176.0,595.92,55.0,3.1,66.75
+2020-10-30 15:00:00,10.64,44.0,339.85,21.0,2.83,69.1
+2020-10-30 16:00:00,8.94,0.0,-0.0,0.0,2.76,76.95
+2020-10-30 17:00:00,7.83,0.0,-0.0,0.0,2.83,82.65
+2020-10-30 18:00:00,6.98,0.0,-0.0,0.0,2.97,85.75
+2020-10-30 19:00:00,6.47,0.0,-0.0,0.0,3.24,76.65
+2020-10-30 20:00:00,6.05,0.0,-0.0,0.0,3.24,79.5
+2020-10-30 21:00:00,5.75,0.0,-0.0,0.0,3.17,82.5
+2020-10-30 22:00:00,5.47,0.0,-0.0,0.0,3.17,79.4
+2020-10-30 23:00:00,5.24,0.0,-0.0,0.0,3.24,82.4
+2020-10-31 00:00:00,5.02,0.0,-0.0,0.0,3.17,82.4
+2020-10-31 01:00:00,4.66,0.0,-0.0,0.0,3.17,82.35
+2020-10-31 02:00:00,4.56,0.0,-0.0,0.0,3.17,82.35
+2020-10-31 03:00:00,4.16,0.0,-0.0,0.0,3.24,82.3
+2020-10-31 04:00:00,3.99,0.0,-0.0,0.0,3.31,82.3
+2020-10-31 05:00:00,3.9,0.0,-0.0,0.0,3.31,85.5
+2020-10-31 06:00:00,3.74,5.0,0.0,5.0,3.45,88.75
+2020-10-31 07:00:00,4.21,62.0,24.04,58.0,3.38,88.8
+2020-10-31 08:00:00,5.03,75.0,0.0,75.0,3.93,85.6
+2020-10-31 09:00:00,6.04,99.0,0.0,99.0,4.07,82.55
+2020-10-31 10:00:00,7.43,76.0,0.0,76.0,3.93,79.65
+2020-10-31 11:00:00,8.7,285.0,208.06,198.0,3.66,76.85
+2020-10-31 12:00:00,10.09,345.0,609.93,112.0,3.45,74.3
+2020-10-31 13:00:00,10.73,196.0,182.42,140.0,3.31,71.7
+2020-10-31 14:00:00,10.83,93.0,60.56,81.0,3.03,74.4
+2020-10-31 15:00:00,10.06,20.0,15.88,19.0,3.03,77.1
+2020-10-31 16:00:00,8.22,0.0,-0.0,0.0,3.5,86.67
+2020-10-31 17:00:00,8.18,0.0,-0.0,0.0,3.53,86.64
+2020-10-31 18:00:00,8.13,0.0,-0.0,0.0,3.56,86.62
+2020-10-31 19:00:00,8.08,0.0,-0.0,0.0,3.59,86.59
+2020-10-31 20:00:00,8.03,0.0,-0.0,0.0,3.62,86.56
+2020-10-31 21:00:00,7.98,0.0,-0.0,0.0,3.65,86.53
+2020-10-31 22:00:00,7.94,0.0,-0.0,0.0,3.69,86.5
+2020-10-31 23:00:00,7.89,0.0,-0.0,0.0,3.72,86.48
+2020-11-01 00:00:00,7.84,0.0,-0.0,0.0,3.75,86.45
+2020-11-01 01:00:00,7.79,0.0,-0.0,0.0,3.78,86.42
+2020-11-01 02:00:00,7.75,0.0,-0.0,0.0,3.81,86.39
+2020-11-01 03:00:00,7.7,0.0,-0.0,0.0,3.84,86.36
+2020-11-01 04:00:00,7.65,0.0,-0.0,0.0,3.87,86.34
+2020-11-01 05:00:00,7.6,0.0,-0.0,0.0,3.9,86.31
+2020-11-01 06:00:00,7.55,0.0,0.0,0.0,3.94,86.28
+2020-11-01 07:00:00,7.51,78.0,80.43,65.0,3.97,86.25
+2020-11-01 08:00:00,8.35,40.0,0.0,40.0,2.69,82.75
+2020-11-01 09:00:00,9.47,46.0,0.0,46.0,2.48,82.9
+2020-11-01 10:00:00,10.15,76.0,0.0,76.0,2.14,82.95
+2020-11-01 11:00:00,10.1,79.0,0.0,79.0,1.66,86.0
+2020-11-01 12:00:00,10.17,74.0,0.0,74.0,1.24,92.5
+2020-11-01 13:00:00,10.18,24.0,0.0,24.0,1.1,92.5
+2020-11-01 14:00:00,10.26,71.0,15.52,68.0,1.17,89.25
+2020-11-01 15:00:00,10.18,25.0,85.66,20.0,1.38,92.5
+2020-11-01 16:00:00,9.79,0.0,-0.0,0.0,1.38,89.2
+2020-11-01 17:00:00,9.36,0.0,-0.0,0.0,1.31,89.15
+2020-11-01 18:00:00,8.99,0.0,-0.0,0.0,1.31,92.45
+2020-11-01 19:00:00,7.97,0.0,-0.0,0.0,1.24,95.8
+2020-11-01 20:00:00,7.94,0.0,-0.0,0.0,1.31,95.8
+2020-11-01 21:00:00,8.18,0.0,-0.0,0.0,1.52,95.8
+2020-11-01 22:00:00,8.19,0.0,-0.0,0.0,1.52,92.4
+2020-11-01 23:00:00,8.05,0.0,-0.0,0.0,1.52,92.4
+2020-11-02 00:00:00,7.74,0.0,-0.0,0.0,1.38,89.05
+2020-11-02 01:00:00,8.06,0.0,-0.0,0.0,0.69,89.05
+2020-11-02 02:00:00,7.51,0.0,-0.0,0.0,0.9,89.0
+2020-11-02 03:00:00,7.08,0.0,-0.0,0.0,1.1,92.35
+2020-11-02 04:00:00,7.04,0.0,-0.0,0.0,1.24,92.35
+2020-11-02 05:00:00,6.99,0.0,-0.0,0.0,1.52,92.35
+2020-11-02 06:00:00,6.93,0.0,0.0,0.0,1.52,92.35
+2020-11-02 07:00:00,7.53,19.0,0.0,19.0,1.24,95.8
+2020-11-02 08:00:00,8.48,70.0,0.0,70.0,1.24,92.4
+2020-11-02 09:00:00,8.96,149.0,19.63,142.0,2.69,89.1
+2020-11-02 10:00:00,9.58,263.0,176.3,192.0,3.1,82.9
+2020-11-02 11:00:00,10.09,278.0,205.91,194.0,2.9,77.1
+2020-11-02 12:00:00,10.56,212.0,99.48,175.0,2.83,71.7
+2020-11-02 13:00:00,10.77,43.0,0.0,43.0,2.41,66.65
+2020-11-02 14:00:00,10.7,15.0,0.0,15.0,1.86,71.7
+2020-11-02 15:00:00,10.07,3.0,0.0,3.0,1.24,74.3
+2020-11-02 16:00:00,8.55,0.0,-0.0,0.0,1.17,85.9
+2020-11-02 17:00:00,7.21,0.0,-0.0,0.0,1.45,85.8
+2020-11-02 18:00:00,5.84,0.0,-0.0,0.0,1.72,88.9
+2020-11-02 19:00:00,5.02,0.0,-0.0,0.0,1.72,95.75
+2020-11-02 20:00:00,4.81,0.0,-0.0,0.0,1.86,95.75
+2020-11-02 21:00:00,4.96,0.0,-0.0,0.0,1.86,95.75
+2020-11-02 22:00:00,4.83,0.0,-0.0,0.0,2.14,92.25
+2020-11-02 23:00:00,5.35,0.0,-0.0,0.0,2.34,92.25
+2020-11-03 00:00:00,6.14,0.0,-0.0,0.0,2.34,88.9
+2020-11-03 01:00:00,5.67,0.0,-0.0,0.0,1.93,92.25
+2020-11-03 02:00:00,5.17,0.0,-0.0,0.0,1.72,95.75
+2020-11-03 03:00:00,5.41,0.0,-0.0,0.0,1.52,92.25
+2020-11-03 04:00:00,5.82,0.0,-0.0,0.0,1.52,92.3
+2020-11-03 05:00:00,5.92,0.0,-0.0,0.0,1.72,92.3
+2020-11-03 06:00:00,5.76,0.0,0.0,0.0,1.72,92.3
+2020-11-03 07:00:00,4.55,34.0,0.0,34.0,1.66,99.4
+2020-11-03 08:00:00,5.97,192.0,287.42,115.0,1.59,92.3
+2020-11-03 09:00:00,7.05,331.0,699.57,85.0,2.07,89.0
+2020-11-03 10:00:00,8.22,351.0,538.09,137.0,2.41,79.75
+2020-11-03 11:00:00,8.96,381.0,680.01,107.0,2.34,74.15
+2020-11-03 12:00:00,9.4,341.0,659.42,99.0,2.21,71.5
+2020-11-03 13:00:00,9.78,270.0,680.79,71.0,2.28,69.0
+2020-11-03 14:00:00,9.69,101.0,119.57,79.0,2.21,74.2
+2020-11-03 15:00:00,9.14,10.0,0.0,10.0,2.21,76.95
+2020-11-03 16:00:00,8.2,0.0,-0.0,0.0,2.28,82.7
+2020-11-03 17:00:00,7.95,0.0,-0.0,0.0,2.62,82.7
+2020-11-03 18:00:00,7.8,0.0,-0.0,0.0,2.34,85.85
+2020-11-03 19:00:00,8.01,0.0,-0.0,0.0,2.48,85.85
+2020-11-03 20:00:00,7.82,0.0,-0.0,0.0,2.48,85.85
+2020-11-03 21:00:00,7.39,0.0,-0.0,0.0,1.86,89.0
+2020-11-03 22:00:00,6.7,0.0,-0.0,0.0,1.72,92.35
+2020-11-03 23:00:00,6.54,0.0,-0.0,0.0,1.66,95.8
+2020-11-04 00:00:00,6.27,0.0,-0.0,0.0,1.72,95.8
+2020-11-04 01:00:00,6.11,0.0,-0.0,0.0,1.31,99.4
+2020-11-04 02:00:00,5.89,0.0,-0.0,0.0,1.24,95.75
+2020-11-04 03:00:00,5.82,0.0,-0.0,0.0,1.1,95.75
+2020-11-04 04:00:00,5.69,0.0,-0.0,0.0,1.03,95.75
+2020-11-04 05:00:00,6.15,0.0,-0.0,0.0,0.69,99.4
+2020-11-04 06:00:00,6.58,0.0,0.0,0.0,0.48,95.8
+2020-11-04 07:00:00,6.24,34.0,0.0,34.0,1.38,99.4
+2020-11-04 08:00:00,6.3,20.0,0.0,20.0,1.66,99.4
+2020-11-04 09:00:00,6.31,33.0,0.0,33.0,2.34,99.4
+2020-11-04 10:00:00,6.15,53.0,0.0,53.0,3.31,99.4
+2020-11-04 11:00:00,6.03,34.0,0.0,34.0,4.83,99.4
+2020-11-04 12:00:00,5.78,99.0,0.0,99.0,4.9,95.75
+2020-11-04 13:00:00,5.51,80.0,0.0,80.0,3.93,99.4
+2020-11-04 14:00:00,5.11,76.0,39.01,69.0,3.93,99.4
+2020-11-04 15:00:00,4.84,15.0,44.39,13.0,6.41,95.75
+2020-11-04 16:00:00,4.85,0.0,-0.0,0.0,6.0,95.75
+2020-11-04 17:00:00,5.26,0.0,-0.0,0.0,6.21,92.25
+2020-11-04 18:00:00,5.62,0.0,-0.0,0.0,6.28,95.75
+2020-11-04 19:00:00,5.76,0.0,-0.0,0.0,6.21,92.3
+2020-11-04 20:00:00,5.92,0.0,-0.0,0.0,5.93,92.3
+2020-11-04 21:00:00,5.92,0.0,-0.0,0.0,5.52,92.3
+2020-11-04 22:00:00,5.89,0.0,-0.0,0.0,5.31,88.9
+2020-11-04 23:00:00,6.0,0.0,-0.0,0.0,5.1,88.9
+2020-11-05 00:00:00,6.03,0.0,-0.0,0.0,4.83,88.9
+2020-11-05 01:00:00,6.44,0.0,-0.0,0.0,4.62,85.7
+2020-11-05 02:00:00,6.51,0.0,-0.0,0.0,4.55,85.7
+2020-11-05 03:00:00,6.51,0.0,-0.0,0.0,4.34,85.7
+2020-11-05 04:00:00,6.49,0.0,-0.0,0.0,4.14,85.7
+2020-11-05 05:00:00,6.46,0.0,-0.0,0.0,4.0,88.95
+2020-11-05 06:00:00,6.32,0.0,0.0,0.0,3.72,88.95
+2020-11-05 07:00:00,6.37,19.0,0.0,19.0,3.66,92.3
+2020-11-05 08:00:00,6.33,41.0,0.0,41.0,3.45,92.3
+2020-11-05 09:00:00,6.3,86.0,0.0,86.0,3.31,95.8
+2020-11-05 10:00:00,6.58,71.0,0.0,71.0,2.69,95.8
+2020-11-05 11:00:00,6.92,100.0,0.0,100.0,2.83,95.8
+2020-11-05 12:00:00,7.34,120.0,2.8,119.0,2.9,92.35
+2020-11-05 13:00:00,7.52,115.0,21.21,109.0,3.1,92.35
+2020-11-05 14:00:00,7.43,72.0,34.3,66.0,3.1,92.35
+2020-11-05 15:00:00,7.23,6.0,0.0,6.0,3.1,89.0
+2020-11-05 16:00:00,6.96,0.0,-0.0,0.0,3.24,89.0
+2020-11-05 17:00:00,6.65,0.0,-0.0,0.0,3.31,88.95
+2020-11-05 18:00:00,6.56,0.0,-0.0,0.0,3.45,88.95
+2020-11-05 19:00:00,6.37,0.0,-0.0,0.0,2.97,88.95
+2020-11-05 20:00:00,5.77,0.0,-0.0,0.0,2.9,92.3
+2020-11-05 21:00:00,5.45,0.0,-0.0,0.0,2.97,92.25
+2020-11-05 22:00:00,5.29,0.0,-0.0,0.0,3.1,92.25
+2020-11-05 23:00:00,5.17,0.0,-0.0,0.0,3.1,95.75
+2020-11-06 00:00:00,5.04,0.0,-0.0,0.0,3.17,95.75
+2020-11-06 01:00:00,4.96,0.0,-0.0,0.0,3.17,95.75
+2020-11-06 02:00:00,4.88,0.0,-0.0,0.0,3.1,95.75
+2020-11-06 03:00:00,4.72,0.0,-0.0,0.0,3.03,92.25
+2020-11-06 04:00:00,4.45,0.0,-0.0,0.0,3.1,95.75
+2020-11-06 05:00:00,4.39,0.0,-0.0,0.0,3.1,95.75
+2020-11-06 06:00:00,4.5,0.0,-0.0,0.0,3.17,95.75
+2020-11-06 07:00:00,5.28,97.0,347.36,49.0,2.9,92.25
+2020-11-06 08:00:00,6.44,212.0,512.87,82.0,2.76,88.95
+2020-11-06 09:00:00,7.66,275.0,421.43,133.0,3.45,85.8
+2020-11-06 10:00:00,8.68,340.0,548.43,130.0,3.93,76.85
+2020-11-06 11:00:00,9.39,298.0,321.97,173.0,3.86,68.9
+2020-11-06 12:00:00,9.87,278.0,368.73,148.0,4.0,66.45
+2020-11-06 13:00:00,10.0,245.0,585.67,82.0,3.79,66.45
+2020-11-06 14:00:00,9.65,122.0,334.21,65.0,3.17,68.9
+2020-11-06 15:00:00,8.69,9.0,0.0,9.0,2.62,74.05
+2020-11-06 16:00:00,7.55,0.0,-0.0,0.0,2.69,76.7
+2020-11-06 17:00:00,6.65,0.0,-0.0,0.0,2.69,82.55
+2020-11-06 18:00:00,6.01,0.0,-0.0,0.0,2.9,82.5
+2020-11-06 19:00:00,5.83,0.0,-0.0,0.0,3.24,82.5
+2020-11-06 20:00:00,5.42,0.0,-0.0,0.0,3.17,82.4
+2020-11-06 21:00:00,5.16,0.0,-0.0,0.0,3.38,82.35
+2020-11-06 22:00:00,4.83,0.0,-0.0,0.0,3.45,82.35
+2020-11-06 23:00:00,4.62,0.0,-0.0,0.0,3.52,85.5
+2020-11-07 00:00:00,4.6,0.0,-0.0,0.0,3.59,82.3
+2020-11-07 01:00:00,4.43,0.0,-0.0,0.0,3.45,82.3
+2020-11-07 02:00:00,4.76,0.0,-0.0,0.0,3.59,76.3
+2020-11-07 03:00:00,5.06,0.0,-0.0,0.0,3.93,76.3
+2020-11-07 04:00:00,5.28,0.0,-0.0,0.0,4.07,73.55
+2020-11-07 05:00:00,5.08,0.0,-0.0,0.0,4.48,73.45
+2020-11-07 06:00:00,5.12,0.0,-0.0,0.0,4.62,76.3
+2020-11-07 07:00:00,5.66,67.0,97.32,54.0,4.9,82.4
+2020-11-07 08:00:00,6.2,56.0,0.0,56.0,5.1,79.5
+2020-11-07 09:00:00,6.48,58.0,0.0,58.0,5.31,82.55
+2020-11-07 10:00:00,6.57,310.0,425.83,149.0,5.38,82.55
+2020-11-07 11:00:00,7.11,62.0,0.0,62.0,4.41,82.6
+2020-11-07 12:00:00,7.37,76.0,0.0,76.0,5.24,79.65
+2020-11-07 13:00:00,7.71,22.0,0.0,22.0,5.1,79.7
+2020-11-07 14:00:00,7.64,13.0,0.0,13.0,5.1,82.65
+2020-11-07 15:00:00,7.55,2.0,0.0,2.0,4.62,82.65
+2020-11-07 16:00:00,7.45,0.0,-0.0,0.0,4.41,82.65
+2020-11-07 17:00:00,7.36,0.0,-0.0,0.0,4.48,82.65
+2020-11-07 18:00:00,7.13,0.0,-0.0,0.0,4.48,85.75
+2020-11-07 19:00:00,6.59,0.0,-0.0,0.0,4.34,88.95
+2020-11-07 20:00:00,6.24,0.0,-0.0,0.0,4.34,88.95
+2020-11-07 21:00:00,6.08,0.0,-0.0,0.0,4.41,88.9
+2020-11-07 22:00:00,6.19,0.0,-0.0,0.0,4.34,85.7
+2020-11-07 23:00:00,6.47,0.0,-0.0,0.0,4.41,88.95
+2020-11-08 00:00:00,6.51,0.0,-0.0,0.0,4.41,88.95
+2020-11-08 01:00:00,6.75,0.0,-0.0,0.0,4.41,85.75
+2020-11-08 02:00:00,6.66,0.0,-0.0,0.0,4.48,88.95
+2020-11-08 03:00:00,6.55,0.0,-0.0,0.0,4.48,88.95
+2020-11-08 04:00:00,6.42,0.0,-0.0,0.0,4.28,85.7
+2020-11-08 05:00:00,6.32,0.0,-0.0,0.0,4.0,85.7
+2020-11-08 06:00:00,6.36,0.0,-0.0,0.0,3.79,85.7
+2020-11-08 07:00:00,6.45,74.0,170.51,52.0,3.93,88.95
+2020-11-08 08:00:00,6.55,114.0,49.17,102.0,3.59,92.3
+2020-11-08 09:00:00,6.78,90.0,0.0,90.0,3.79,89.0
+2020-11-08 10:00:00,7.31,121.0,2.68,120.0,4.41,85.8
+2020-11-08 11:00:00,7.82,172.0,29.04,161.0,4.0,82.7
+2020-11-08 12:00:00,8.35,192.0,93.21,160.0,3.59,79.75
+2020-11-08 13:00:00,8.64,157.0,126.21,123.0,3.24,79.75
+2020-11-08 14:00:00,8.77,37.0,0.0,37.0,3.1,76.95
+2020-11-08 15:00:00,8.36,3.0,0.0,3.0,2.83,76.85
+2020-11-08 16:00:00,7.94,0.0,-0.0,0.0,2.55,79.7
+2020-11-08 17:00:00,7.7,0.0,-0.0,0.0,2.28,82.65
+2020-11-08 18:00:00,7.4,0.0,-0.0,0.0,2.14,85.8
+2020-11-08 19:00:00,6.67,0.0,-0.0,0.0,2.28,85.7
+2020-11-08 20:00:00,6.69,0.0,-0.0,0.0,2.34,82.6
+2020-11-08 21:00:00,6.69,0.0,-0.0,0.0,2.41,85.7
+2020-11-08 22:00:00,6.67,0.0,-0.0,0.0,2.34,85.7
+2020-11-08 23:00:00,6.71,0.0,-0.0,0.0,2.21,82.6
+2020-11-09 00:00:00,6.65,0.0,-0.0,0.0,2.0,85.7
+2020-11-09 01:00:00,6.4,0.0,-0.0,0.0,1.86,85.7
+2020-11-09 02:00:00,6.56,0.0,-0.0,0.0,1.79,85.7
+2020-11-09 03:00:00,6.59,0.0,-0.0,0.0,1.66,85.7
+2020-11-09 04:00:00,6.62,0.0,-0.0,0.0,1.45,85.7
+2020-11-09 05:00:00,6.59,0.0,-0.0,0.0,1.38,88.95
+2020-11-09 06:00:00,6.44,0.0,-0.0,0.0,1.31,88.95
+2020-11-09 07:00:00,4.71,82.0,289.17,46.0,1.31,95.75
+2020-11-09 08:00:00,6.37,187.0,413.54,88.0,0.83,88.95
+2020-11-09 09:00:00,7.99,264.0,440.09,122.0,0.83,79.7
+2020-11-09 10:00:00,8.77,357.0,746.05,82.0,0.76,74.15
+2020-11-09 11:00:00,9.67,353.0,689.64,95.0,1.86,71.5
+2020-11-09 12:00:00,9.93,307.0,613.96,99.0,2.41,66.45
+2020-11-09 13:00:00,9.98,227.0,550.85,81.0,2.55,66.45
+2020-11-09 14:00:00,9.58,110.0,316.61,60.0,2.07,68.9
+2020-11-09 15:00:00,8.74,5.0,0.0,5.0,2.07,71.4
+2020-11-09 16:00:00,7.58,0.0,-0.0,0.0,2.41,79.65
+2020-11-09 17:00:00,6.92,0.0,-0.0,0.0,2.76,82.6
+2020-11-09 18:00:00,6.37,0.0,-0.0,0.0,2.97,82.55
+2020-11-09 19:00:00,5.81,0.0,-0.0,0.0,2.55,85.65
+2020-11-09 20:00:00,5.17,0.0,-0.0,0.0,2.69,88.85
+2020-11-09 21:00:00,4.86,0.0,-0.0,0.0,2.97,85.55
+2020-11-09 22:00:00,4.79,0.0,-0.0,0.0,3.24,82.35
+2020-11-09 23:00:00,4.56,0.0,-0.0,0.0,3.03,85.5
+2020-11-10 00:00:00,4.15,0.0,-0.0,0.0,2.9,88.75
+2020-11-10 01:00:00,3.42,0.0,-0.0,0.0,2.83,85.45
+2020-11-10 02:00:00,3.11,0.0,-0.0,0.0,2.69,88.7
+2020-11-10 03:00:00,2.75,0.0,-0.0,0.0,2.83,88.7
+2020-11-10 04:00:00,2.57,0.0,-0.0,0.0,3.1,88.65
+2020-11-10 05:00:00,2.45,0.0,-0.0,0.0,3.1,88.65
+2020-11-10 06:00:00,2.29,0.0,-0.0,0.0,2.97,88.65
+2020-11-10 07:00:00,2.16,59.0,91.66,48.0,2.76,92.15
+2020-11-10 08:00:00,3.27,129.0,102.22,105.0,2.41,88.75
+2020-11-10 09:00:00,4.9,238.0,314.46,138.0,2.69,88.85
+2020-11-10 10:00:00,6.23,330.0,596.22,113.0,2.55,82.55
+2020-11-10 11:00:00,7.32,261.0,235.43,174.0,2.28,76.7
+2020-11-10 12:00:00,7.78,235.0,242.26,154.0,2.0,73.95
+2020-11-10 13:00:00,8.08,201.0,375.77,103.0,2.0,76.8
+2020-11-10 14:00:00,7.9,96.0,214.43,63.0,1.72,76.8
+2020-11-10 15:00:00,7.05,0.0,0.0,0.0,1.79,82.6
+2020-11-10 16:00:00,5.7,0.0,-0.0,0.0,2.14,85.65
+2020-11-10 17:00:00,4.85,0.0,-0.0,0.0,2.21,88.85
+2020-11-10 18:00:00,4.28,0.0,-0.0,0.0,2.14,92.2
+2020-11-10 19:00:00,3.85,0.0,-0.0,0.0,2.14,92.15
+2020-11-10 20:00:00,3.64,0.0,-0.0,0.0,2.07,92.15
+2020-11-10 21:00:00,3.79,0.0,-0.0,0.0,1.93,92.15
+2020-11-10 22:00:00,3.38,0.0,-0.0,0.0,1.72,92.15
+2020-11-10 23:00:00,2.57,0.0,-0.0,0.0,1.79,95.7
+2020-11-11 00:00:00,2.02,0.0,-0.0,0.0,1.79,95.65
+2020-11-11 01:00:00,1.61,0.0,-0.0,0.0,1.79,95.65
+2020-11-11 02:00:00,1.25,0.0,-0.0,0.0,1.79,95.65
+2020-11-11 03:00:00,0.97,0.0,-0.0,0.0,1.72,99.35
+2020-11-11 04:00:00,0.88,0.0,-0.0,0.0,1.86,99.35
+2020-11-11 05:00:00,1.09,0.0,-0.0,0.0,2.0,99.35
+2020-11-11 06:00:00,1.16,0.0,-0.0,0.0,1.86,95.65
+2020-11-11 07:00:00,1.88,75.0,294.22,41.0,1.79,95.65
+2020-11-11 08:00:00,3.14,184.0,451.71,80.0,1.72,95.7
+2020-11-11 09:00:00,4.53,252.0,421.19,120.0,1.66,92.2
+2020-11-11 10:00:00,5.49,303.0,475.83,132.0,1.45,88.85
+2020-11-11 11:00:00,6.81,341.0,679.38,93.0,1.24,82.6
+2020-11-11 12:00:00,7.77,303.0,651.53,88.0,1.24,76.8
+2020-11-11 13:00:00,8.39,219.0,553.31,77.0,1.17,74.05
+2020-11-11 14:00:00,8.31,107.0,360.08,53.0,0.76,74.05
+2020-11-11 15:00:00,7.46,0.0,0.0,0.0,0.62,82.65
+2020-11-11 16:00:00,6.16,0.0,-0.0,0.0,0.9,88.9
+2020-11-11 17:00:00,4.93,0.0,-0.0,0.0,1.03,92.25
+2020-11-11 18:00:00,4.8,0.0,-0.0,0.0,0.97,92.25
+2020-11-11 19:00:00,0.88,0.0,-0.0,0.0,1.72,95.65
+2020-11-11 20:00:00,0.2,0.0,-0.0,0.0,1.59,95.65
+2020-11-11 21:00:00,0.3,0.0,-0.0,0.0,1.24,99.4
+2020-11-11 22:00:00,0.36,0.0,-0.0,0.0,1.24,99.4
+2020-11-11 23:00:00,0.37,0.0,-0.0,0.0,1.31,99.4
+2020-11-12 00:00:00,0.35,0.0,-0.0,0.0,1.45,99.4
+2020-11-12 01:00:00,0.33,0.0,-0.0,0.0,1.31,99.4
+2020-11-12 02:00:00,0.45,0.0,-0.0,0.0,1.31,99.4
+2020-11-12 03:00:00,0.53,0.0,-0.0,0.0,1.38,99.4
+2020-11-12 04:00:00,0.68,0.0,-0.0,0.0,1.45,95.65
+2020-11-12 05:00:00,0.73,0.0,-0.0,0.0,1.59,95.65
+2020-11-12 06:00:00,0.71,0.0,-0.0,0.0,1.79,95.65
+2020-11-12 07:00:00,0.56,54.0,98.96,43.0,2.0,99.4
+2020-11-12 08:00:00,1.02,177.0,420.86,82.0,2.07,99.35
+2020-11-12 09:00:00,2.15,259.0,482.43,110.0,2.14,95.65
+2020-11-12 10:00:00,3.73,337.0,707.32,86.0,2.41,92.15
+2020-11-12 11:00:00,5.21,342.0,698.81,90.0,2.83,82.4
+2020-11-12 12:00:00,6.22,297.0,632.44,91.0,2.9,79.5
+2020-11-12 13:00:00,6.61,221.0,593.9,71.0,2.97,79.5
+2020-11-12 14:00:00,6.44,102.0,328.47,54.0,2.9,79.5
+2020-11-12 15:00:00,5.38,0.0,0.0,0.0,2.83,85.6
+2020-11-12 16:00:00,4.37,0.0,-0.0,0.0,2.9,92.2
+2020-11-12 17:00:00,3.84,0.0,-0.0,0.0,2.9,92.15
+2020-11-12 18:00:00,3.63,0.0,-0.0,0.0,2.76,92.15
+2020-11-12 19:00:00,3.19,0.0,-0.0,0.0,2.76,88.75
+2020-11-12 20:00:00,3.17,0.0,-0.0,0.0,2.76,88.75
+2020-11-12 21:00:00,3.27,0.0,-0.0,0.0,2.97,88.75
+2020-11-12 22:00:00,3.19,0.0,-0.0,0.0,3.24,88.75
+2020-11-12 23:00:00,3.22,0.0,-0.0,0.0,3.45,88.75
+2020-11-13 00:00:00,3.3,0.0,-0.0,0.0,3.38,88.75
+2020-11-13 01:00:00,3.78,0.0,-0.0,0.0,3.31,92.15
+2020-11-13 02:00:00,3.69,0.0,-0.0,0.0,3.03,92.15
+2020-11-13 03:00:00,3.57,0.0,-0.0,0.0,2.76,92.15
+2020-11-13 04:00:00,3.7,0.0,-0.0,0.0,2.76,95.7
+2020-11-13 05:00:00,3.71,0.0,-0.0,0.0,2.9,95.7
+2020-11-13 06:00:00,3.87,0.0,-0.0,0.0,3.03,95.7
+2020-11-13 07:00:00,3.87,39.0,28.09,36.0,2.69,88.75
+2020-11-13 08:00:00,4.28,98.0,40.67,89.0,2.28,88.8
+2020-11-13 09:00:00,5.24,233.0,364.69,122.0,2.21,85.6
+2020-11-13 10:00:00,6.23,146.0,19.98,139.0,1.79,82.55
+2020-11-13 11:00:00,7.34,260.0,286.3,158.0,1.72,79.65
+2020-11-13 12:00:00,8.21,167.0,71.53,144.0,1.86,74.05
+2020-11-13 13:00:00,8.33,73.0,0.0,73.0,1.86,74.05
+2020-11-13 14:00:00,8.01,21.0,0.0,21.0,1.72,79.7
+2020-11-13 15:00:00,7.28,0.0,0.0,0.0,1.79,79.65
+2020-11-13 16:00:00,6.34,0.0,-0.0,0.0,1.86,85.7
+2020-11-13 17:00:00,5.34,0.0,-0.0,0.0,1.86,92.25
+2020-11-13 18:00:00,4.85,0.0,-0.0,0.0,1.79,95.75
+2020-11-13 19:00:00,5.36,0.0,-0.0,0.0,1.59,92.25
+2020-11-13 20:00:00,4.92,0.0,-0.0,0.0,1.52,95.75
+2020-11-13 21:00:00,4.84,0.0,-0.0,0.0,1.45,95.75
+2020-11-13 22:00:00,4.63,0.0,-0.0,0.0,1.45,99.4
+2020-11-13 23:00:00,4.49,0.0,-0.0,0.0,1.38,99.4
+2020-11-14 00:00:00,4.51,0.0,-0.0,0.0,1.31,99.4
+2020-11-14 01:00:00,4.12,0.0,-0.0,0.0,1.24,99.4
+2020-11-14 02:00:00,3.96,0.0,-0.0,0.0,1.17,99.4
+2020-11-14 03:00:00,3.76,0.0,-0.0,0.0,1.24,99.4
+2020-11-14 04:00:00,3.92,0.0,-0.0,0.0,1.17,99.4
+2020-11-14 05:00:00,4.37,0.0,-0.0,0.0,1.03,95.75
+2020-11-14 06:00:00,4.32,0.0,-0.0,0.0,1.1,95.75
+2020-11-14 07:00:00,4.12,69.0,361.02,32.0,0.97,100.0
+2020-11-14 08:00:00,5.33,119.0,115.27,94.0,0.28,95.75
+2020-11-14 09:00:00,6.47,99.0,3.33,98.0,0.41,92.3
+2020-11-14 10:00:00,7.24,154.0,28.9,144.0,0.69,85.8
+2020-11-14 11:00:00,7.78,157.0,31.25,146.0,1.17,85.85
+2020-11-14 12:00:00,7.81,56.0,0.0,56.0,1.45,85.85
+2020-11-14 13:00:00,7.79,57.0,0.0,57.0,1.72,85.85
+2020-11-14 14:00:00,7.6,40.0,7.21,39.0,1.86,89.0
+2020-11-14 15:00:00,7.17,0.0,0.0,0.0,1.72,92.35
+2020-11-14 16:00:00,6.74,0.0,-0.0,0.0,1.79,92.35
+2020-11-14 17:00:00,6.41,0.0,-0.0,0.0,2.0,95.8
+2020-11-14 18:00:00,6.14,0.0,-0.0,0.0,2.14,99.4
+2020-11-14 19:00:00,5.51,0.0,-0.0,0.0,2.69,95.75
+2020-11-14 20:00:00,5.21,0.0,-0.0,0.0,2.34,92.25
+2020-11-14 21:00:00,4.97,0.0,-0.0,0.0,2.07,95.75
+2020-11-14 22:00:00,4.74,0.0,-0.0,0.0,1.93,95.75
+2020-11-14 23:00:00,4.46,0.0,-0.0,0.0,2.21,99.4
+2020-11-15 00:00:00,4.05,0.0,-0.0,0.0,2.69,99.4
+2020-11-15 01:00:00,3.49,0.0,-0.0,0.0,2.76,95.7
+2020-11-15 02:00:00,3.16,0.0,-0.0,0.0,2.48,99.4
+2020-11-15 03:00:00,2.99,0.0,-0.0,0.0,2.28,95.7
+2020-11-15 04:00:00,2.85,0.0,-0.0,0.0,2.28,95.7
+2020-11-15 05:00:00,2.76,0.0,-0.0,0.0,2.41,92.15
+2020-11-15 06:00:00,2.67,0.0,-0.0,0.0,2.55,92.15
+2020-11-15 07:00:00,3.15,25.0,0.0,25.0,2.48,92.15
+2020-11-15 08:00:00,3.49,58.0,0.0,58.0,2.41,88.75
+2020-11-15 09:00:00,3.93,49.0,0.0,49.0,2.28,92.15
+2020-11-15 10:00:00,4.7,62.0,0.0,62.0,2.21,85.55
+2020-11-15 11:00:00,5.43,71.0,0.0,71.0,2.14,82.4
+2020-11-15 12:00:00,6.16,61.0,0.0,61.0,2.07,82.5
+2020-11-15 13:00:00,6.66,66.0,0.0,66.0,2.0,79.5
+2020-11-15 14:00:00,6.72,37.0,0.0,37.0,1.93,76.65
+2020-11-15 15:00:00,6.01,0.0,0.0,0.0,1.86,82.5
+2020-11-15 16:00:00,5.02,0.0,-0.0,0.0,2.0,88.85
+2020-11-15 17:00:00,4.26,0.0,-0.0,0.0,2.14,92.2
+2020-11-15 18:00:00,3.69,0.0,-0.0,0.0,2.14,92.15
+2020-11-15 19:00:00,3.31,0.0,-0.0,0.0,1.93,92.15
+2020-11-15 20:00:00,2.91,0.0,-0.0,0.0,1.93,95.7
+2020-11-15 21:00:00,2.64,0.0,-0.0,0.0,2.07,95.7
+2020-11-15 22:00:00,2.47,0.0,-0.0,0.0,2.14,95.7
+2020-11-15 23:00:00,2.76,0.0,-0.0,0.0,2.14,92.15
+2020-11-16 00:00:00,3.14,0.0,-0.0,0.0,2.14,95.7
+2020-11-16 01:00:00,3.59,0.0,-0.0,0.0,2.07,95.7
+2020-11-16 02:00:00,3.97,0.0,-0.0,0.0,2.0,99.4
+2020-11-16 03:00:00,4.32,0.0,-0.0,0.0,1.93,99.4
+2020-11-16 04:00:00,4.63,0.0,-0.0,0.0,2.07,99.4
+2020-11-16 05:00:00,4.93,0.0,-0.0,0.0,2.34,95.75
+2020-11-16 06:00:00,4.98,0.0,-0.0,0.0,2.69,95.75
+2020-11-16 07:00:00,5.21,41.0,74.45,34.0,3.03,92.25
+2020-11-16 08:00:00,5.7,114.0,110.44,91.0,3.17,88.9
+2020-11-16 09:00:00,6.56,214.0,302.1,126.0,4.55,85.7
+2020-11-16 10:00:00,7.09,245.0,275.55,152.0,4.21,82.6
+2020-11-16 11:00:00,7.53,252.0,282.21,155.0,3.45,79.65
+2020-11-16 12:00:00,7.86,237.0,348.93,129.0,2.97,76.8
+2020-11-16 13:00:00,8.13,135.0,118.02,107.0,2.62,76.8
+2020-11-16 14:00:00,8.09,57.0,53.11,50.0,1.86,76.8
+2020-11-16 15:00:00,7.7,0.0,0.0,0.0,1.72,76.8
+2020-11-16 16:00:00,7.17,0.0,-0.0,0.0,1.79,82.6
+2020-11-16 17:00:00,6.76,0.0,-0.0,0.0,1.86,82.6
+2020-11-16 18:00:00,6.49,0.0,-0.0,0.0,1.86,85.7
+2020-11-16 19:00:00,6.07,0.0,-0.0,0.0,1.24,88.9
+2020-11-16 20:00:00,5.7,0.0,-0.0,0.0,1.38,88.9
+2020-11-16 21:00:00,5.26,0.0,-0.0,0.0,1.31,92.25
+2020-11-16 22:00:00,4.48,0.0,-0.0,0.0,1.31,95.75
+2020-11-16 23:00:00,4.2,0.0,-0.0,0.0,1.17,95.75
+2020-11-17 00:00:00,3.79,0.0,-0.0,0.0,1.17,99.4
+2020-11-17 01:00:00,3.74,0.0,-0.0,0.0,1.03,99.4
+2020-11-17 02:00:00,3.72,0.0,-0.0,0.0,0.9,99.4
+2020-11-17 03:00:00,3.91,0.0,-0.0,0.0,0.69,100.0
+2020-11-17 04:00:00,3.86,0.0,-0.0,0.0,0.76,99.4
+2020-11-17 05:00:00,3.91,0.0,-0.0,0.0,0.69,100.0
+2020-11-17 06:00:00,3.98,0.0,-0.0,0.0,0.76,100.0
+2020-11-17 07:00:00,4.44,8.0,0.0,8.0,1.1,99.4
+2020-11-17 08:00:00,4.92,82.0,24.51,77.0,1.79,95.75
+2020-11-17 09:00:00,5.26,98.0,6.97,96.0,2.14,88.85
+2020-11-17 10:00:00,5.4,30.0,0.0,30.0,2.28,88.85
+2020-11-17 11:00:00,5.57,57.0,0.0,57.0,2.97,85.6
+2020-11-17 12:00:00,5.72,37.0,0.0,37.0,3.1,82.5
+2020-11-17 13:00:00,5.81,18.0,0.0,18.0,3.17,79.4
+2020-11-17 14:00:00,5.6,13.0,0.0,13.0,2.83,82.4
+2020-11-17 15:00:00,5.44,0.0,-0.0,0.0,2.9,79.35
+2020-11-17 16:00:00,5.2,0.0,-0.0,0.0,2.83,79.35
+2020-11-17 17:00:00,4.95,0.0,-0.0,0.0,2.83,82.35
+2020-11-17 18:00:00,5.09,0.0,-0.0,0.0,2.9,85.55
+2020-11-17 19:00:00,5.29,0.0,-0.0,0.0,3.38,82.4
+2020-11-17 20:00:00,5.63,0.0,-0.0,0.0,3.79,85.6
+2020-11-17 21:00:00,5.64,0.0,-0.0,0.0,3.93,88.85
+2020-11-17 22:00:00,5.62,0.0,-0.0,0.0,4.0,88.85
+2020-11-17 23:00:00,5.47,0.0,-0.0,0.0,3.79,88.85
+2020-11-18 00:00:00,5.34,0.0,-0.0,0.0,3.72,88.85
+2020-11-18 01:00:00,5.64,0.0,-0.0,0.0,3.72,92.25
+2020-11-18 02:00:00,5.5,0.0,-0.0,0.0,3.79,92.25
+2020-11-18 03:00:00,5.38,0.0,-0.0,0.0,3.72,88.85
+2020-11-18 04:00:00,5.18,0.0,-0.0,0.0,3.72,88.85
+2020-11-18 05:00:00,4.82,0.0,-0.0,0.0,3.72,92.25
+2020-11-18 06:00:00,4.8,0.0,-0.0,0.0,3.79,92.25
+2020-11-18 07:00:00,5.51,47.0,174.87,32.0,3.59,92.25
+2020-11-18 08:00:00,6.13,166.0,545.35,57.0,3.72,88.9
+2020-11-18 09:00:00,7.05,92.0,3.53,91.0,3.59,89.0
+2020-11-18 10:00:00,7.57,77.0,0.0,77.0,3.86,85.8
+2020-11-18 11:00:00,7.64,140.0,20.85,133.0,3.79,85.8
+2020-11-18 12:00:00,8.38,189.0,162.26,140.0,5.59,76.85
+2020-11-18 13:00:00,8.62,103.0,39.1,94.0,4.76,76.85
+2020-11-18 14:00:00,8.26,69.0,151.67,50.0,4.07,76.85
+2020-11-18 15:00:00,7.49,0.0,-0.0,0.0,3.86,79.65
+2020-11-18 16:00:00,7.11,0.0,-0.0,0.0,3.93,79.55
+2020-11-18 17:00:00,6.92,0.0,-0.0,0.0,4.28,76.65
+2020-11-18 18:00:00,6.7,0.0,-0.0,0.0,4.48,76.65
+2020-11-18 19:00:00,6.37,0.0,-0.0,0.0,4.62,85.7
+2020-11-18 20:00:00,6.58,0.0,-0.0,0.0,4.83,85.7
+2020-11-18 21:00:00,6.79,0.0,-0.0,0.0,4.83,82.6
+2020-11-18 22:00:00,7.08,0.0,-0.0,0.0,5.1,82.6
+2020-11-18 23:00:00,7.39,0.0,-0.0,0.0,5.24,79.65
+2020-11-19 00:00:00,7.64,0.0,-0.0,0.0,5.38,82.65
+2020-11-19 01:00:00,7.2,0.0,-0.0,0.0,5.38,79.65
+2020-11-19 02:00:00,7.3,0.0,-0.0,0.0,5.24,82.65
+2020-11-19 03:00:00,7.47,0.0,-0.0,0.0,5.17,85.8
+2020-11-19 04:00:00,7.7,0.0,-0.0,0.0,5.1,89.0
+2020-11-19 05:00:00,7.87,0.0,-0.0,0.0,5.03,85.85
+2020-11-19 06:00:00,7.97,0.0,-0.0,0.0,5.17,89.05
+2020-11-19 07:00:00,7.75,25.0,12.23,24.0,5.17,85.85
+2020-11-19 08:00:00,7.93,74.0,20.43,70.0,5.24,89.05
+2020-11-19 09:00:00,8.17,45.0,0.0,45.0,5.45,89.05
+2020-11-19 10:00:00,8.39,109.0,3.07,108.0,4.97,85.9
+2020-11-19 11:00:00,8.56,67.0,0.0,67.0,5.79,89.1
+2020-11-19 12:00:00,8.73,104.0,6.7,102.0,6.41,85.95
+2020-11-19 13:00:00,8.92,38.0,0.0,38.0,5.66,89.1
+2020-11-19 14:00:00,8.97,31.0,0.0,31.0,5.03,89.1
+2020-11-19 15:00:00,8.78,0.0,-0.0,0.0,4.83,89.1
+2020-11-19 16:00:00,8.58,0.0,-0.0,0.0,4.83,92.4
+2020-11-19 17:00:00,8.42,0.0,-0.0,0.0,4.83,92.4
+2020-11-19 18:00:00,8.31,0.0,-0.0,0.0,4.69,92.4
+2020-11-19 19:00:00,7.91,0.0,-0.0,0.0,4.69,92.4
+2020-11-19 20:00:00,7.8,0.0,-0.0,0.0,4.69,92.4
+2020-11-19 21:00:00,7.87,0.0,-0.0,0.0,4.62,92.4
+2020-11-19 22:00:00,7.92,0.0,-0.0,0.0,4.48,92.4
+2020-11-19 23:00:00,7.91,0.0,-0.0,0.0,4.34,92.4
+2020-11-20 00:00:00,8.01,0.0,-0.0,0.0,4.34,95.8
+2020-11-20 01:00:00,8.27,0.0,-0.0,0.0,4.21,92.4
+2020-11-20 02:00:00,8.31,0.0,-0.0,0.0,4.14,92.4
+2020-11-20 03:00:00,8.3,0.0,-0.0,0.0,4.07,92.4
+2020-11-20 04:00:00,8.35,0.0,-0.0,0.0,4.0,95.85
+2020-11-20 05:00:00,8.35,0.0,-0.0,0.0,3.86,95.85
+2020-11-20 06:00:00,8.33,0.0,-0.0,0.0,3.72,95.85
+2020-11-20 07:00:00,8.48,16.0,0.0,16.0,3.79,95.85
+2020-11-20 08:00:00,8.52,50.0,0.0,50.0,3.59,95.85
+2020-11-20 09:00:00,8.7,30.0,0.0,30.0,3.1,95.85
+2020-11-20 10:00:00,8.86,33.0,0.0,33.0,3.03,92.45
+2020-11-20 11:00:00,9.22,52.0,0.0,52.0,3.52,92.45
+2020-11-20 12:00:00,9.34,48.0,0.0,48.0,3.31,92.45
+2020-11-20 13:00:00,9.39,38.0,0.0,38.0,2.9,89.15
+2020-11-20 14:00:00,9.28,13.0,0.0,13.0,2.97,89.15
+2020-11-20 15:00:00,9.02,0.0,-0.0,0.0,2.9,89.1
+2020-11-20 16:00:00,8.6,0.0,-0.0,0.0,2.9,89.1
+2020-11-20 17:00:00,8.17,0.0,-0.0,0.0,2.97,89.05
+2020-11-20 18:00:00,7.62,0.0,-0.0,0.0,2.97,89.0
+2020-11-20 19:00:00,7.04,0.0,-0.0,0.0,2.76,89.0
+2020-11-20 20:00:00,6.74,0.0,-0.0,0.0,2.83,85.75
+2020-11-20 21:00:00,6.46,0.0,-0.0,0.0,2.83,88.95
+2020-11-20 22:00:00,6.03,0.0,-0.0,0.0,2.76,88.9
+2020-11-20 23:00:00,5.54,0.0,-0.0,0.0,2.62,92.25
+2020-11-21 00:00:00,5.6,0.0,-0.0,0.0,2.62,92.25
+2020-11-21 01:00:00,5.41,0.0,-0.0,0.0,2.55,88.85
+2020-11-21 02:00:00,5.29,0.0,-0.0,0.0,2.41,88.85
+2020-11-21 03:00:00,5.06,0.0,-0.0,0.0,2.34,92.25
+2020-11-21 04:00:00,4.84,0.0,-0.0,0.0,2.34,88.85
+2020-11-21 05:00:00,4.82,0.0,-0.0,0.0,2.28,88.85
+2020-11-21 06:00:00,4.54,0.0,-0.0,0.0,2.34,88.8
+2020-11-21 07:00:00,4.29,4.0,0.0,4.0,2.41,92.2
+2020-11-21 08:00:00,4.76,14.0,0.0,14.0,2.41,88.85
+2020-11-21 09:00:00,5.55,45.0,0.0,45.0,3.1,85.6
+2020-11-21 10:00:00,6.09,71.0,0.0,71.0,3.52,85.65
+2020-11-21 11:00:00,6.33,98.0,0.0,98.0,3.1,85.7
+2020-11-21 12:00:00,6.43,55.0,0.0,55.0,2.97,85.7
+2020-11-21 13:00:00,6.47,68.0,4.54,67.0,2.83,85.7
+2020-11-21 14:00:00,6.45,33.0,8.6,32.0,2.83,85.7
+2020-11-21 15:00:00,6.32,0.0,-0.0,0.0,2.0,85.7
+2020-11-21 16:00:00,6.19,0.0,-0.0,0.0,1.86,85.7
+2020-11-21 17:00:00,6.07,0.0,-0.0,0.0,1.93,88.9
+2020-11-21 18:00:00,5.94,0.0,-0.0,0.0,1.93,88.9
+2020-11-21 19:00:00,5.75,0.0,-0.0,0.0,1.59,92.3
+2020-11-21 20:00:00,5.71,0.0,-0.0,0.0,1.52,95.75
+2020-11-21 21:00:00,5.61,0.0,-0.0,0.0,1.66,99.4
+2020-11-21 22:00:00,5.51,0.0,-0.0,0.0,1.86,99.4
+2020-11-21 23:00:00,5.42,0.0,-0.0,0.0,1.66,99.4
+2020-11-22 00:00:00,5.3,0.0,-0.0,0.0,1.72,99.4
+2020-11-22 01:00:00,5.51,0.0,-0.0,0.0,1.72,99.4
+2020-11-22 02:00:00,5.27,0.0,-0.0,0.0,1.72,99.4
+2020-11-22 03:00:00,5.04,0.0,-0.0,0.0,1.52,99.4
+2020-11-22 04:00:00,4.83,0.0,-0.0,0.0,1.52,99.4
+2020-11-22 05:00:00,4.66,0.0,-0.0,0.0,1.59,99.4
+2020-11-22 06:00:00,4.54,0.0,-0.0,0.0,1.72,99.4
+2020-11-22 07:00:00,4.28,21.0,14.28,20.0,1.79,99.4
+2020-11-22 08:00:00,4.28,46.0,0.0,46.0,2.07,99.4
+2020-11-22 09:00:00,4.31,43.0,0.0,43.0,2.41,99.4
+2020-11-22 10:00:00,4.32,134.0,22.3,127.0,2.48,99.4
+2020-11-22 11:00:00,4.46,57.0,0.0,57.0,2.28,99.4
+2020-11-22 12:00:00,4.28,74.0,0.0,74.0,2.83,95.75
+2020-11-22 13:00:00,4.19,110.0,73.63,94.0,3.38,92.2
+2020-11-22 14:00:00,3.9,32.0,0.0,32.0,3.45,95.7
+2020-11-22 15:00:00,3.42,0.0,-0.0,0.0,2.76,92.15
+2020-11-22 16:00:00,2.85,0.0,-0.0,0.0,2.76,92.15
+2020-11-22 17:00:00,2.21,0.0,-0.0,0.0,2.69,92.15
+2020-11-22 18:00:00,1.57,0.0,-0.0,0.0,2.41,95.65
+2020-11-22 19:00:00,1.74,0.0,-0.0,0.0,2.28,92.1
+2020-11-22 20:00:00,1.34,0.0,-0.0,0.0,1.93,92.05
+2020-11-22 21:00:00,1.07,0.0,-0.0,0.0,1.79,92.05
+2020-11-22 22:00:00,0.65,0.0,-0.0,0.0,1.72,92.05
+2020-11-22 23:00:00,-0.2,0.0,-0.0,0.0,1.86,92.0
+2020-11-23 00:00:00,-0.75,0.0,-0.0,0.0,1.93,91.95
+2020-11-23 01:00:00,-1.18,0.0,-0.0,0.0,2.0,91.95
+2020-11-23 02:00:00,-1.5,0.0,-0.0,0.0,2.14,91.9
+2020-11-23 03:00:00,-1.58,0.0,-0.0,0.0,2.21,91.9
+2020-11-23 04:00:00,-1.6,0.0,-0.0,0.0,2.34,88.35
+2020-11-23 05:00:00,-1.39,0.0,-0.0,0.0,2.55,88.35
+2020-11-23 06:00:00,-1.1,0.0,-0.0,0.0,2.62,88.4
+2020-11-23 07:00:00,-0.38,32.0,135.88,23.0,2.83,88.45
+2020-11-23 08:00:00,0.79,113.0,199.86,77.0,2.83,85.2
+2020-11-23 09:00:00,2.01,66.0,0.0,66.0,2.83,85.3
+2020-11-23 10:00:00,2.8,57.0,0.0,57.0,3.03,85.4
+2020-11-23 11:00:00,3.27,181.0,100.77,149.0,3.17,85.45
+2020-11-23 12:00:00,3.48,99.0,7.02,97.0,3.17,88.75
+2020-11-23 13:00:00,3.7,69.0,4.67,68.0,2.97,88.75
+2020-11-23 14:00:00,3.69,48.0,54.14,42.0,2.83,92.15
+2020-11-23 15:00:00,3.55,0.0,-0.0,0.0,2.62,92.15
+2020-11-23 16:00:00,3.38,0.0,-0.0,0.0,2.41,92.15
+2020-11-23 17:00:00,3.43,0.0,-0.0,0.0,2.28,95.7
+2020-11-23 18:00:00,3.55,0.0,-0.0,0.0,2.21,95.7
+2020-11-23 19:00:00,3.4,0.0,-0.0,0.0,2.21,95.7
+2020-11-23 20:00:00,3.47,0.0,-0.0,0.0,2.21,95.7
+2020-11-23 21:00:00,3.55,0.0,-0.0,0.0,2.28,95.7
+2020-11-23 22:00:00,3.64,0.0,-0.0,0.0,2.34,99.4
+2020-11-23 23:00:00,3.71,0.0,-0.0,0.0,2.34,99.4
+2020-11-24 00:00:00,3.8,0.0,-0.0,0.0,2.28,99.4
+2020-11-24 01:00:00,3.79,0.0,-0.0,0.0,2.28,99.4
+2020-11-24 02:00:00,3.81,0.0,-0.0,0.0,2.21,99.4
+2020-11-24 03:00:00,3.88,0.0,-0.0,0.0,2.21,99.4
+2020-11-24 04:00:00,3.86,0.0,-0.0,0.0,2.21,99.4
+2020-11-24 05:00:00,3.87,0.0,-0.0,0.0,2.14,99.4
+2020-11-24 06:00:00,3.91,0.0,-0.0,0.0,1.93,99.4
+2020-11-24 07:00:00,4.0,19.0,15.99,18.0,1.45,100.0
+2020-11-24 08:00:00,4.28,76.0,39.68,69.0,1.38,99.4
+2020-11-24 09:00:00,4.53,75.0,0.0,75.0,1.38,99.4
+2020-11-24 10:00:00,4.84,102.0,3.26,101.0,1.17,95.75
+2020-11-24 11:00:00,5.32,60.0,0.0,60.0,0.97,92.25
+2020-11-24 12:00:00,5.38,37.0,0.0,37.0,0.69,92.25
+2020-11-24 13:00:00,5.54,33.0,0.0,33.0,0.14,88.85
+2020-11-24 14:00:00,5.49,14.0,0.0,14.0,0.55,88.85
+2020-11-24 15:00:00,4.97,0.0,-0.0,0.0,1.24,92.25
+2020-11-24 16:00:00,4.28,0.0,-0.0,0.0,1.45,92.2
+2020-11-24 17:00:00,3.6,0.0,-0.0,0.0,1.66,95.7
+2020-11-24 18:00:00,3.37,0.0,-0.0,0.0,1.72,92.15
+2020-11-24 19:00:00,3.67,0.0,-0.0,0.0,1.93,92.15
+2020-11-24 20:00:00,3.03,0.0,-0.0,0.0,2.07,88.7
+2020-11-24 21:00:00,2.97,0.0,-0.0,0.0,2.21,85.4
+2020-11-24 22:00:00,2.67,0.0,-0.0,0.0,2.28,85.4
+2020-11-24 23:00:00,1.88,0.0,-0.0,0.0,2.34,88.65
+2020-11-25 00:00:00,1.19,0.0,-0.0,0.0,2.34,88.6
+2020-11-25 01:00:00,0.71,0.0,-0.0,0.0,2.34,88.55
+2020-11-25 02:00:00,0.3,0.0,-0.0,0.0,2.34,92.0
+2020-11-25 03:00:00,-0.31,0.0,-0.0,0.0,2.41,92.0
+2020-11-25 04:00:00,-0.7,0.0,-0.0,0.0,2.48,91.95
+2020-11-25 05:00:00,-0.87,0.0,-0.0,0.0,2.48,91.95
+2020-11-25 06:00:00,-0.87,0.0,-0.0,0.0,2.34,91.95
+2020-11-25 07:00:00,0.24,20.0,33.96,18.0,1.86,92.0
+2020-11-25 08:00:00,0.84,69.0,23.15,65.0,1.86,88.55
+2020-11-25 09:00:00,1.52,68.0,0.0,68.0,2.07,85.25
+2020-11-25 10:00:00,2.01,60.0,0.0,60.0,2.07,78.95
+2020-11-25 11:00:00,2.47,54.0,0.0,54.0,2.14,76.0
+2020-11-25 12:00:00,2.99,36.0,0.0,36.0,2.14,73.2
+2020-11-25 13:00:00,3.12,29.0,0.0,29.0,2.14,70.4
+2020-11-25 14:00:00,3.08,29.0,0.0,29.0,2.28,70.4
+2020-11-25 15:00:00,2.68,0.0,-0.0,0.0,1.93,73.2
+2020-11-25 16:00:00,2.32,0.0,-0.0,0.0,2.21,76.0
+2020-11-25 17:00:00,1.94,0.0,-0.0,0.0,2.21,78.95
+2020-11-25 18:00:00,1.69,0.0,-0.0,0.0,2.28,78.95
+2020-11-25 19:00:00,1.25,0.0,-0.0,0.0,2.48,82.0
+2020-11-25 20:00:00,1.44,0.0,-0.0,0.0,2.41,82.0
+2020-11-25 21:00:00,1.35,0.0,-0.0,0.0,2.48,82.0
+2020-11-25 22:00:00,1.46,0.0,-0.0,0.0,2.48,82.0
+2020-11-25 23:00:00,1.79,0.0,-0.0,0.0,2.48,78.95
+2020-11-26 00:00:00,2.02,0.0,-0.0,0.0,2.41,82.05
+2020-11-26 01:00:00,2.43,0.0,-0.0,0.0,2.28,82.15
+2020-11-26 02:00:00,2.48,0.0,-0.0,0.0,2.28,82.15
+2020-11-26 03:00:00,2.61,0.0,-0.0,0.0,2.28,85.35
+2020-11-26 04:00:00,2.59,0.0,-0.0,0.0,2.14,85.35
+2020-11-26 05:00:00,2.22,0.0,-0.0,0.0,1.86,85.35
+2020-11-26 06:00:00,1.72,0.0,-0.0,0.0,1.86,88.65
+2020-11-26 07:00:00,1.8,24.0,90.37,19.0,2.0,88.65
+2020-11-26 08:00:00,1.93,42.0,0.0,42.0,1.86,85.3
+2020-11-26 09:00:00,2.28,67.0,0.0,67.0,1.93,82.15
+2020-11-26 10:00:00,2.62,95.0,3.33,94.0,1.86,82.15
+2020-11-26 11:00:00,3.05,106.0,3.25,105.0,1.72,76.1
+2020-11-26 12:00:00,3.42,84.0,0.0,84.0,1.66,73.3
+2020-11-26 13:00:00,3.88,41.0,0.0,41.0,1.72,70.5
+2020-11-26 14:00:00,3.79,10.0,0.0,10.0,1.24,70.5
+2020-11-26 15:00:00,3.32,0.0,-0.0,0.0,0.76,76.15
+2020-11-26 16:00:00,2.8,0.0,-0.0,0.0,1.1,79.1
+2020-11-26 17:00:00,2.15,0.0,-0.0,0.0,1.31,82.15
+2020-11-26 18:00:00,0.96,0.0,-0.0,0.0,1.59,92.05
+2020-11-26 19:00:00,0.53,0.0,-0.0,0.0,1.79,92.0
+2020-11-26 20:00:00,0.01,0.0,-0.0,0.0,1.93,92.0
+2020-11-26 21:00:00,-0.72,0.0,-0.0,0.0,2.0,88.45
+2020-11-26 22:00:00,-1.24,0.0,-0.0,0.0,2.0,88.4
+2020-11-26 23:00:00,-1.5,0.0,-0.0,0.0,2.07,88.35
+2020-11-27 00:00:00,-1.83,0.0,-0.0,0.0,2.14,88.35
+2020-11-27 01:00:00,-1.75,0.0,-0.0,0.0,2.21,88.35
+2020-11-27 02:00:00,-1.94,0.0,-0.0,0.0,2.41,88.3
+2020-11-27 03:00:00,-1.73,0.0,-0.0,0.0,2.62,88.35
+2020-11-27 04:00:00,-1.42,0.0,-0.0,0.0,2.83,88.35
+2020-11-27 05:00:00,-1.16,0.0,-0.0,0.0,2.97,88.4
+2020-11-27 06:00:00,-0.89,0.0,-0.0,0.0,3.03,88.4
+2020-11-27 07:00:00,-0.39,20.0,57.86,17.0,2.9,88.45
+2020-11-27 08:00:00,0.54,131.0,476.74,52.0,2.97,88.5
+2020-11-27 09:00:00,1.65,83.0,4.01,82.0,2.9,82.05
+2020-11-27 10:00:00,2.48,139.0,40.45,127.0,2.97,82.15
+2020-11-27 11:00:00,3.09,135.0,29.53,126.0,3.03,79.1
+2020-11-27 12:00:00,3.57,113.0,21.97,107.0,3.03,79.15
+2020-11-27 13:00:00,3.66,125.0,171.86,90.0,3.03,79.15
+2020-11-27 14:00:00,3.82,18.0,0.0,18.0,2.83,82.25
+2020-11-27 15:00:00,3.42,0.0,-0.0,0.0,2.69,79.15
+2020-11-27 16:00:00,3.4,0.0,-0.0,0.0,2.55,79.15
+2020-11-27 17:00:00,2.79,0.0,-0.0,0.0,2.34,82.2
+2020-11-27 18:00:00,1.86,0.0,-0.0,0.0,2.34,85.3
+2020-11-27 19:00:00,0.62,0.0,-0.0,0.0,2.07,95.65
+2020-11-27 20:00:00,-0.02,0.0,-0.0,0.0,2.14,92.0
+2020-11-27 21:00:00,-0.09,0.0,-0.0,0.0,1.93,92.0
+2020-11-27 22:00:00,-0.03,0.0,-0.0,0.0,1.72,92.0
+2020-11-27 23:00:00,-0.8,0.0,-0.0,0.0,1.72,91.95
+2020-11-28 00:00:00,-1.26,0.0,-0.0,0.0,1.72,91.95
+2020-11-28 01:00:00,-1.16,0.0,-0.0,0.0,1.66,91.95
+2020-11-28 02:00:00,-1.9,0.0,-0.0,0.0,1.79,95.55
+2020-11-28 03:00:00,-2.25,0.0,-0.0,0.0,1.86,91.85
+2020-11-28 04:00:00,-2.41,0.0,-0.0,0.0,1.86,91.85
+2020-11-28 05:00:00,-2.31,0.0,-0.0,0.0,1.66,88.3
+2020-11-28 06:00:00,-2.13,0.0,-0.0,0.0,1.52,88.3
+2020-11-28 07:00:00,-2.41,9.0,0.0,9.0,1.38,95.55
+2020-11-28 08:00:00,-0.67,58.0,12.32,56.0,0.69,95.6
+2020-11-28 09:00:00,0.46,76.0,4.07,75.0,0.55,95.65
+2020-11-28 10:00:00,1.35,87.0,0.0,87.0,0.21,88.6
+2020-11-28 11:00:00,1.73,112.0,6.63,110.0,0.21,85.3
+2020-11-28 12:00:00,1.96,129.0,44.38,117.0,0.41,85.3
+2020-11-28 13:00:00,1.98,96.0,54.65,85.0,0.76,85.3
+2020-11-28 14:00:00,1.67,49.0,110.88,38.0,0.76,88.65
+2020-11-28 15:00:00,0.76,0.0,-0.0,0.0,0.9,92.05
+2020-11-28 16:00:00,0.0,0.0,-0.0,0.0,1.1,95.6
+2020-11-28 17:00:00,-0.88,0.0,-0.0,0.0,1.38,95.6
+2020-11-28 18:00:00,-1.18,0.0,-0.0,0.0,1.45,91.95
+2020-11-28 19:00:00,-0.76,0.0,-0.0,0.0,1.38,95.6
+2020-11-28 20:00:00,-0.61,0.0,-0.0,0.0,1.52,95.6
+2020-11-28 21:00:00,-0.69,0.0,-0.0,0.0,1.52,95.6
+2020-11-28 22:00:00,-1.36,0.0,-0.0,0.0,1.45,91.95
+2020-11-28 23:00:00,-1.4,0.0,-0.0,0.0,1.31,95.6
+2020-11-29 00:00:00,-1.94,0.0,-0.0,0.0,1.52,95.55
+2020-11-29 01:00:00,-1.79,0.0,-0.0,0.0,1.72,91.9
+2020-11-29 02:00:00,-1.57,0.0,-0.0,0.0,2.07,95.6
+2020-11-29 03:00:00,-1.55,0.0,-0.0,0.0,2.21,95.6
+2020-11-29 04:00:00,-1.24,0.0,-0.0,0.0,2.07,95.6
+2020-11-29 05:00:00,-0.5,0.0,-0.0,0.0,3.1,95.6
+2020-11-29 06:00:00,-0.17,0.0,-0.0,0.0,2.9,92.0
+2020-11-29 07:00:00,-1.14,8.0,0.0,8.0,2.0,95.6
+2020-11-29 08:00:00,-0.26,59.0,18.87,56.0,3.59,92.0
+2020-11-29 09:00:00,0.39,56.0,0.0,56.0,3.66,92.0
+2020-11-29 10:00:00,1.08,83.0,0.0,83.0,4.0,92.05
+2020-11-29 11:00:00,1.28,94.0,0.0,94.0,4.48,88.6
+2020-11-29 12:00:00,1.53,74.0,0.0,74.0,4.62,82.0
+2020-11-29 13:00:00,1.62,58.0,0.0,58.0,4.48,82.0
+2020-11-29 14:00:00,1.37,48.0,113.14,37.0,3.52,85.25
+2020-11-29 15:00:00,1.03,0.0,-0.0,0.0,3.72,92.05
+2020-11-29 16:00:00,0.94,0.0,-0.0,0.0,4.0,92.05
+2020-11-29 17:00:00,0.79,0.0,-0.0,0.0,4.28,92.05
+2020-11-29 18:00:00,0.73,0.0,-0.0,0.0,4.41,92.05
+2020-11-29 19:00:00,0.31,0.0,-0.0,0.0,3.72,92.0
+2020-11-29 20:00:00,0.17,0.0,-0.0,0.0,3.79,88.5
+2020-11-29 21:00:00,0.32,0.0,-0.0,0.0,3.79,92.0
+2020-11-29 22:00:00,0.5,0.0,-0.0,0.0,4.07,95.65
+2020-11-29 23:00:00,0.66,0.0,-0.0,0.0,4.34,92.05
+2020-11-30 00:00:00,0.69,0.0,-0.0,0.0,4.48,88.55
+2020-11-30 01:00:00,0.43,0.0,-0.0,0.0,4.28,88.5
+2020-11-30 02:00:00,0.33,0.0,-0.0,0.0,4.28,85.15
+2020-11-30 03:00:00,0.15,0.0,-0.0,0.0,4.34,81.9
+2020-11-30 04:00:00,0.34,0.0,-0.0,0.0,4.28,78.75
+2020-11-30 05:00:00,0.69,0.0,-0.0,0.0,4.34,78.8
+2020-11-30 06:00:00,1.17,0.0,-0.0,0.0,4.69,82.0
+2020-11-30 07:00:00,1.5,5.0,0.0,5.0,5.31,85.25
+2020-11-30 08:00:00,1.71,44.0,0.0,44.0,5.93,78.95
+2020-11-30 09:00:00,2.06,56.0,0.0,56.0,6.83,78.95
+2020-11-30 10:00:00,2.59,64.0,0.0,64.0,7.45,79.0
+2020-11-30 11:00:00,2.72,69.0,0.0,69.0,7.72,79.1
+2020-11-30 12:00:00,2.71,85.0,3.77,84.0,7.31,82.2
+2020-11-30 13:00:00,2.67,46.0,0.0,46.0,6.83,88.7
+2020-11-30 14:00:00,2.75,6.0,0.0,6.0,6.76,92.15
+2020-11-30 15:00:00,3.32,0.0,-0.0,0.0,6.55,92.15
+2020-11-30 16:00:00,5.02,0.0,-0.0,0.0,7.33,95.8
+2020-11-30 17:00:00,4.61,0.0,-0.0,0.0,6.85,95.6
+2020-11-30 18:00:00,4.2,0.0,-0.0,0.0,6.37,95.41
+2020-11-30 19:00:00,3.79,0.0,-0.0,0.0,5.89,95.21
+2020-11-30 20:00:00,3.37,0.0,-0.0,0.0,5.4,95.02
+2020-11-30 21:00:00,2.96,0.0,-0.0,0.0,4.92,94.82
+2020-11-30 22:00:00,2.55,0.0,-0.0,0.0,4.44,94.62
+2020-11-30 23:00:00,2.14,0.0,-0.0,0.0,3.96,94.43
+2020-12-01 00:00:00,1.73,0.0,-0.0,0.0,3.47,94.23
+2020-12-01 01:00:00,1.31,0.0,-0.0,0.0,2.99,94.04
+2020-12-01 02:00:00,0.9,0.0,-0.0,0.0,2.51,93.84
+2020-12-01 03:00:00,0.49,0.0,-0.0,0.0,2.03,93.65
+2020-12-01 04:00:00,0.08,0.0,-0.0,0.0,1.54,93.45
+2020-12-01 05:00:00,-0.33,0.0,-0.0,0.0,1.06,93.25
+2020-12-01 06:00:00,-0.75,0.0,-0.0,0.0,0.58,93.06
+2020-12-01 07:00:00,-1.16,2.0,0.0,2.0,0.1,92.86
+2020-12-01 08:00:00,0.83,73.0,65.5,63.0,1.31,92.05
+2020-12-01 09:00:00,2.35,150.0,173.32,109.0,1.31,85.35
+2020-12-01 10:00:00,2.75,168.0,112.42,136.0,2.48,73.2
+2020-12-01 11:00:00,2.97,247.0,459.66,112.0,2.62,73.2
+2020-12-01 12:00:00,3.1,250.0,722.3,60.0,2.28,70.4
+2020-12-01 13:00:00,3.07,166.0,559.51,57.0,1.93,70.4
+2020-12-01 14:00:00,2.87,58.0,256.31,34.0,1.79,67.7
+2020-12-01 15:00:00,2.19,0.0,-0.0,0.0,1.52,75.95
+2020-12-01 16:00:00,1.25,0.0,-0.0,0.0,1.66,78.9
+2020-12-01 17:00:00,0.55,0.0,-0.0,0.0,1.59,85.15
+2020-12-01 18:00:00,0.22,0.0,-0.0,0.0,1.31,85.15
+2020-12-01 19:00:00,-0.13,0.0,-0.0,0.0,1.24,88.45
+2020-12-01 20:00:00,-0.17,0.0,-0.0,0.0,1.1,88.45
+2020-12-01 21:00:00,-0.04,0.0,-0.0,0.0,0.97,88.45
+2020-12-01 22:00:00,0.84,0.0,-0.0,0.0,0.69,81.95
+2020-12-01 23:00:00,0.75,0.0,-0.0,0.0,0.48,85.2
+2020-12-02 00:00:00,-0.35,0.0,-0.0,0.0,0.97,91.95
+2020-12-02 01:00:00,-0.53,0.0,-0.0,0.0,1.1,95.6
+2020-12-02 02:00:00,-0.71,0.0,-0.0,0.0,1.24,95.6
+2020-12-02 03:00:00,-0.68,0.0,-0.0,0.0,1.45,95.6
+2020-12-02 04:00:00,-0.26,0.0,-0.0,0.0,1.59,95.6
+2020-12-02 05:00:00,0.39,0.0,-0.0,0.0,2.34,95.65
+2020-12-02 06:00:00,0.42,0.0,-0.0,0.0,2.07,99.4
+2020-12-02 07:00:00,0.46,5.0,0.0,5.0,2.41,99.4
+2020-12-02 08:00:00,0.74,68.0,53.46,60.0,4.0,92.05
+2020-12-02 09:00:00,1.57,71.0,0.0,71.0,4.14,88.6
+2020-12-02 10:00:00,2.51,97.0,3.55,96.0,4.83,82.15
+2020-12-02 11:00:00,2.89,78.0,0.0,78.0,5.38,82.2
+2020-12-02 12:00:00,3.05,75.0,0.0,75.0,5.45,82.2
+2020-12-02 13:00:00,2.97,44.0,0.0,44.0,5.31,82.2
+2020-12-02 14:00:00,3.06,32.0,21.73,30.0,4.41,82.2
+2020-12-02 15:00:00,2.89,0.0,-0.0,0.0,3.86,85.4
+2020-12-02 16:00:00,2.77,0.0,-0.0,0.0,3.79,85.4
+2020-12-02 17:00:00,2.69,0.0,-0.0,0.0,4.14,88.65
+2020-12-02 18:00:00,2.6,0.0,-0.0,0.0,4.28,92.15
+2020-12-02 19:00:00,2.78,0.0,-0.0,0.0,5.24,92.15
+2020-12-02 20:00:00,2.23,0.0,-0.0,0.0,4.21,92.15
+2020-12-02 21:00:00,2.4,0.0,-0.0,0.0,4.34,88.65
+2020-12-02 22:00:00,2.37,0.0,-0.0,0.0,4.48,95.7
+2020-12-02 23:00:00,2.08,0.0,-0.0,0.0,4.76,95.65
+2020-12-03 00:00:00,1.67,0.0,-0.0,0.0,4.41,99.4
+2020-12-03 01:00:00,1.45,0.0,-0.0,0.0,4.21,95.65
+2020-12-03 02:00:00,1.17,0.0,-0.0,0.0,3.38,99.35
+2020-12-03 03:00:00,1.01,0.0,-0.0,0.0,2.9,99.35
+2020-12-03 04:00:00,1.01,0.0,-0.0,0.0,2.55,99.35
+2020-12-03 05:00:00,0.8,0.0,-0.0,0.0,2.07,95.65
+2020-12-03 06:00:00,0.48,0.0,-0.0,0.0,1.66,99.4
+2020-12-03 07:00:00,0.77,2.0,0.0,2.0,1.24,99.35
+2020-12-03 08:00:00,1.57,69.0,61.35,60.0,1.59,95.65
+2020-12-03 09:00:00,2.3,50.0,0.0,50.0,1.66,88.65
+2020-12-03 10:00:00,3.16,135.0,46.54,122.0,1.86,85.4
+2020-12-03 11:00:00,3.67,152.0,69.24,132.0,1.93,82.25
+2020-12-03 12:00:00,3.85,191.0,309.18,111.0,2.21,82.3
+2020-12-03 13:00:00,4.04,0.0,0.0,0.0,2.41,85.5
+2020-12-03 14:00:00,3.85,48.0,154.65,34.0,1.93,88.8
+2020-12-03 15:00:00,3.61,0.0,-0.0,0.0,1.93,95.7
+2020-12-03 16:00:00,3.51,0.0,-0.0,0.0,1.93,95.7
+2020-12-03 17:00:00,3.45,0.0,-0.0,0.0,2.07,95.7
+2020-12-03 18:00:00,3.43,0.0,-0.0,0.0,2.28,95.7
+2020-12-03 19:00:00,3.8,0.0,-0.0,0.0,2.41,95.75
+2020-12-03 20:00:00,3.71,0.0,-0.0,0.0,2.62,92.2
+2020-12-03 21:00:00,3.72,0.0,-0.0,0.0,2.55,92.2
+2020-12-03 22:00:00,3.71,0.0,-0.0,0.0,2.41,92.2
+2020-12-03 23:00:00,3.46,0.0,-0.0,0.0,2.34,92.15
+2020-12-04 00:00:00,3.44,0.0,-0.0,0.0,2.21,92.15
+2020-12-04 01:00:00,2.73,0.0,-0.0,0.0,2.0,88.7
+2020-12-04 02:00:00,2.29,0.0,-0.0,0.0,1.86,88.65
+2020-12-04 03:00:00,2.04,0.0,-0.0,0.0,1.72,88.65
+2020-12-04 04:00:00,1.67,0.0,-0.0,0.0,1.66,92.05
+2020-12-04 05:00:00,1.05,0.0,-0.0,0.0,1.72,92.05
+2020-12-04 06:00:00,0.97,0.0,-0.0,0.0,1.66,92.05
+2020-12-04 07:00:00,0.9,4.0,0.0,4.0,1.93,92.05
+2020-12-04 08:00:00,0.98,113.0,500.5,41.0,1.72,92.05
+2020-12-04 09:00:00,2.1,205.0,666.3,53.0,1.86,88.65
+2020-12-04 10:00:00,3.22,254.0,679.18,66.0,2.14,79.15
+2020-12-04 11:00:00,4.15,247.0,537.37,93.0,2.41,76.25
+2020-12-04 12:00:00,4.83,233.0,669.83,61.0,2.48,73.45
+2020-12-04 13:00:00,4.98,158.0,554.26,53.0,2.34,73.45
+2020-12-04 14:00:00,4.43,64.0,448.68,24.0,2.14,73.45
+2020-12-04 15:00:00,3.19,0.0,-0.0,0.0,2.55,82.2
+2020-12-04 16:00:00,2.26,0.0,-0.0,0.0,2.9,82.15
+2020-12-04 17:00:00,1.81,0.0,-0.0,0.0,3.03,85.3
+2020-12-04 18:00:00,1.59,0.0,-0.0,0.0,3.17,85.25
+2020-12-04 19:00:00,1.28,0.0,-0.0,0.0,3.24,82.0
+2020-12-04 20:00:00,1.09,0.0,-0.0,0.0,3.31,81.95
+2020-12-04 21:00:00,0.67,0.0,-0.0,0.0,3.31,81.9
+2020-12-04 22:00:00,0.35,0.0,-0.0,0.0,3.31,78.75
+2020-12-04 23:00:00,0.08,0.0,-0.0,0.0,3.31,81.8
+2020-12-05 00:00:00,-0.17,0.0,-0.0,0.0,3.45,78.65
+2020-12-05 01:00:00,-0.48,0.0,-0.0,0.0,3.59,81.75
+2020-12-05 02:00:00,-0.54,0.0,-0.0,0.0,3.72,81.75
+2020-12-05 03:00:00,-0.55,0.0,-0.0,0.0,3.79,81.75
+2020-12-05 04:00:00,-0.72,0.0,-0.0,0.0,3.79,81.75
+2020-12-05 05:00:00,-0.92,0.0,-0.0,0.0,3.72,81.7
+2020-12-05 06:00:00,-1.07,0.0,-0.0,0.0,3.59,81.7
+2020-12-05 07:00:00,-1.18,3.0,0.0,3.0,3.66,81.7
+2020-12-05 08:00:00,-0.81,110.0,474.79,43.0,3.66,81.75
+2020-12-05 09:00:00,0.14,207.0,682.85,53.0,3.52,81.8
+2020-12-05 10:00:00,1.33,259.0,714.26,63.0,3.38,75.85
+2020-12-05 11:00:00,2.42,270.0,724.23,64.0,3.1,73.1
+2020-12-05 12:00:00,3.11,243.0,745.3,53.0,2.9,70.4
+2020-12-05 13:00:00,3.23,162.0,606.72,48.0,2.55,70.5
+2020-12-05 14:00:00,2.53,62.0,432.32,24.0,2.48,76.0
+2020-12-05 15:00:00,1.24,0.0,-0.0,0.0,2.69,78.9
+2020-12-05 16:00:00,0.5,0.0,-0.0,0.0,2.69,81.9
+2020-12-05 17:00:00,0.23,0.0,-0.0,0.0,2.83,81.9
+2020-12-05 18:00:00,0.1,0.0,-0.0,0.0,2.97,81.8
+2020-12-05 19:00:00,-1.02,0.0,-0.0,0.0,3.1,81.7
+2020-12-05 20:00:00,-1.09,0.0,-0.0,0.0,2.97,78.5
+2020-12-05 21:00:00,-1.22,0.0,-0.0,0.0,2.76,78.5
+2020-12-05 22:00:00,-1.19,0.0,-0.0,0.0,2.76,75.45
+2020-12-05 23:00:00,-1.05,0.0,-0.0,0.0,2.83,75.45
+2020-12-06 00:00:00,-1.0,0.0,-0.0,0.0,2.83,75.45
+2020-12-06 01:00:00,-0.8,0.0,-0.0,0.0,2.83,72.6
+2020-12-06 02:00:00,-0.47,0.0,-0.0,0.0,2.9,72.6
+2020-12-06 03:00:00,-0.44,0.0,-0.0,0.0,3.03,69.75
+2020-12-06 04:00:00,-0.03,0.0,-0.0,0.0,3.31,64.45
+2020-12-06 05:00:00,0.38,0.0,-0.0,0.0,3.52,59.6
+2020-12-06 06:00:00,0.57,0.0,-0.0,0.0,3.45,57.2
+2020-12-06 07:00:00,0.06,3.0,0.0,3.0,3.72,61.9
+2020-12-06 08:00:00,0.64,109.0,476.61,43.0,3.72,62.0
+2020-12-06 09:00:00,2.09,203.0,663.57,55.0,3.72,62.35
+2020-12-06 10:00:00,3.56,223.0,433.61,105.0,3.72,60.3
+2020-12-06 11:00:00,4.7,216.0,332.83,122.0,3.79,60.5
+2020-12-06 12:00:00,5.32,217.0,521.32,85.0,3.86,58.3
+2020-12-06 13:00:00,5.27,148.0,445.11,65.0,3.72,58.3
+2020-12-06 14:00:00,4.56,30.0,23.05,28.0,3.72,58.2
+2020-12-06 15:00:00,3.66,0.0,-0.0,0.0,4.0,62.7
+2020-12-06 16:00:00,3.29,0.0,-0.0,0.0,4.34,65.2
+2020-12-06 17:00:00,3.29,0.0,-0.0,0.0,4.62,67.8
+2020-12-06 18:00:00,3.56,0.0,-0.0,0.0,4.69,73.3
+2020-12-06 19:00:00,3.11,0.0,-0.0,0.0,4.76,70.4
+2020-12-06 20:00:00,3.65,0.0,-0.0,0.0,4.9,73.3
+2020-12-06 21:00:00,4.32,0.0,-0.0,0.0,5.03,70.7
+2020-12-06 22:00:00,4.73,0.0,-0.0,0.0,5.03,76.3
+2020-12-06 23:00:00,5.04,0.0,-0.0,0.0,5.17,82.35
+2020-12-07 00:00:00,5.12,0.0,-0.0,0.0,5.31,88.85
+2020-12-07 01:00:00,5.73,0.0,-0.0,0.0,5.45,85.65
+2020-12-07 02:00:00,5.59,0.0,-0.0,0.0,5.52,88.85
+2020-12-07 03:00:00,5.57,0.0,-0.0,0.0,5.45,88.85
+2020-12-07 04:00:00,5.79,0.0,-0.0,0.0,5.52,85.65
+2020-12-07 05:00:00,6.11,0.0,-0.0,0.0,5.59,85.65
+2020-12-07 06:00:00,6.38,0.0,-0.0,0.0,5.86,85.7
+2020-12-07 07:00:00,7.05,0.0,0.0,0.0,6.07,85.75
+2020-12-07 08:00:00,7.23,61.0,58.85,53.0,6.0,85.75
+2020-12-07 09:00:00,7.39,65.0,0.0,65.0,5.72,85.8
+2020-12-07 10:00:00,7.59,94.0,7.41,92.0,6.0,85.8
+2020-12-07 11:00:00,7.81,39.0,0.0,39.0,5.93,82.7
+2020-12-07 12:00:00,7.82,33.0,0.0,33.0,6.0,82.7
+2020-12-07 13:00:00,7.67,77.0,32.4,71.0,5.38,85.8
+2020-12-07 14:00:00,7.27,15.0,0.0,15.0,4.97,82.65
+2020-12-07 15:00:00,7.0,0.0,-0.0,0.0,4.83,85.75
+2020-12-07 16:00:00,6.8,0.0,-0.0,0.0,4.69,85.75
+2020-12-07 17:00:00,6.73,0.0,-0.0,0.0,4.62,85.7
+2020-12-07 18:00:00,6.7,0.0,-0.0,0.0,4.62,85.7
+2020-12-07 19:00:00,6.72,0.0,-0.0,0.0,4.62,88.95
+2020-12-07 20:00:00,6.66,0.0,-0.0,0.0,4.55,85.7
+2020-12-07 21:00:00,6.58,0.0,-0.0,0.0,4.41,85.7
+2020-12-07 22:00:00,6.46,0.0,-0.0,0.0,4.28,85.7
+2020-12-07 23:00:00,6.31,0.0,-0.0,0.0,4.21,82.55
+2020-12-08 00:00:00,6.27,0.0,-0.0,0.0,4.0,82.55
+2020-12-08 01:00:00,5.97,0.0,-0.0,0.0,3.86,85.65
+2020-12-08 02:00:00,5.94,0.0,-0.0,0.0,3.72,85.65
+2020-12-08 03:00:00,5.98,0.0,-0.0,0.0,3.72,85.65
+2020-12-08 04:00:00,5.95,0.0,-0.0,0.0,3.79,85.65
+2020-12-08 05:00:00,5.96,0.0,-0.0,0.0,4.0,85.65
+2020-12-08 06:00:00,5.73,0.0,-0.0,0.0,4.07,82.5
+2020-12-08 07:00:00,6.4,0.0,0.0,0.0,4.21,82.55
+2020-12-08 08:00:00,6.69,84.0,239.69,52.0,4.34,82.55
+2020-12-08 09:00:00,7.19,105.0,59.53,92.0,4.55,79.55
+2020-12-08 10:00:00,7.9,219.0,459.08,96.0,3.86,76.8
+2020-12-08 11:00:00,8.39,159.0,107.62,129.0,4.21,74.05
+2020-12-08 12:00:00,8.68,70.0,0.0,70.0,4.07,76.85
+2020-12-08 13:00:00,8.93,87.0,59.78,76.0,5.86,71.4
+2020-12-08 14:00:00,8.95,29.0,23.56,27.0,5.45,71.4
+2020-12-08 15:00:00,8.83,0.0,-0.0,0.0,5.31,71.4
+2020-12-08 16:00:00,8.98,0.0,-0.0,0.0,5.17,74.15
+2020-12-08 17:00:00,9.26,0.0,-0.0,0.0,5.03,76.95
+2020-12-08 18:00:00,9.45,0.0,-0.0,0.0,4.97,77.0
+2020-12-08 19:00:00,9.92,0.0,-0.0,0.0,4.83,74.3
+2020-12-08 20:00:00,9.97,0.0,-0.0,0.0,4.69,74.3
+2020-12-08 21:00:00,9.89,0.0,-0.0,0.0,4.41,77.1
+2020-12-08 22:00:00,9.72,0.0,-0.0,0.0,4.07,79.9
+2020-12-08 23:00:00,9.55,0.0,-0.0,0.0,3.66,79.9
+2020-12-09 00:00:00,9.32,0.0,-0.0,0.0,3.72,82.9
+2020-12-09 01:00:00,9.19,0.0,-0.0,0.0,3.86,89.1
+2020-12-09 02:00:00,8.72,0.0,-0.0,0.0,3.93,85.9
+2020-12-09 03:00:00,8.15,0.0,-0.0,0.0,4.41,85.85
+2020-12-09 04:00:00,7.43,0.0,-0.0,0.0,4.21,82.65
+2020-12-09 05:00:00,6.84,0.0,-0.0,0.0,3.93,82.6
+2020-12-09 06:00:00,6.13,0.0,-0.0,0.0,3.66,85.65
+2020-12-09 07:00:00,6.3,0.0,0.0,0.0,3.52,82.55
+2020-12-09 08:00:00,6.88,104.0,525.99,35.0,3.79,82.6
+2020-12-09 09:00:00,7.59,145.0,235.86,94.0,3.93,79.65
+2020-12-09 10:00:00,8.09,176.0,203.01,122.0,4.14,76.8
+2020-12-09 11:00:00,8.5,195.0,259.84,123.0,3.86,71.35
+2020-12-09 12:00:00,8.83,57.0,0.0,57.0,4.0,68.8
+2020-12-09 13:00:00,9.07,37.0,0.0,37.0,4.14,66.25
+2020-12-09 14:00:00,8.36,7.0,0.0,7.0,3.72,68.7
+2020-12-09 15:00:00,7.7,0.0,-0.0,0.0,3.52,71.15
+2020-12-09 16:00:00,7.03,0.0,-0.0,0.0,3.45,73.8
+2020-12-09 17:00:00,6.59,0.0,-0.0,0.0,3.59,79.5
+2020-12-09 18:00:00,6.27,0.0,-0.0,0.0,3.59,79.5
+2020-12-09 19:00:00,6.07,0.0,-0.0,0.0,3.59,85.65
+2020-12-09 20:00:00,6.13,0.0,-0.0,0.0,4.21,85.65
+2020-12-09 21:00:00,5.83,0.0,-0.0,0.0,4.69,85.65
+2020-12-09 22:00:00,5.47,0.0,-0.0,0.0,4.55,88.85
+2020-12-09 23:00:00,4.95,0.0,-0.0,0.0,4.55,92.25
+2020-12-10 00:00:00,4.48,0.0,-0.0,0.0,4.97,92.25
+2020-12-10 01:00:00,4.16,0.0,-0.0,0.0,4.9,95.75
+2020-12-10 02:00:00,3.55,0.0,-0.0,0.0,4.9,92.15
+2020-12-10 03:00:00,3.05,0.0,-0.0,0.0,4.9,92.15
+2020-12-10 04:00:00,2.68,0.0,-0.0,0.0,5.1,95.7
+2020-12-10 05:00:00,2.35,0.0,-0.0,0.0,4.69,92.15
+2020-12-10 06:00:00,2.27,0.0,-0.0,0.0,4.69,92.15
+2020-12-10 07:00:00,2.34,0.0,0.0,0.0,4.34,92.15
+2020-12-10 08:00:00,2.5,105.0,550.55,34.0,4.0,92.15
+2020-12-10 09:00:00,2.84,136.0,182.08,97.0,4.76,88.7
+2020-12-10 10:00:00,3.19,193.0,287.67,117.0,4.55,88.7
+2020-12-10 11:00:00,3.69,237.0,515.3,95.0,4.34,85.45
+2020-12-10 12:00:00,4.02,207.0,484.77,87.0,4.34,79.2
+2020-12-10 13:00:00,4.01,56.0,5.49,55.0,3.45,79.2
+2020-12-10 14:00:00,3.82,34.0,47.92,30.0,2.62,79.2
+2020-12-10 15:00:00,3.39,0.0,-0.0,0.0,2.07,85.45
+2020-12-10 16:00:00,2.71,0.0,-0.0,0.0,1.86,85.4
+2020-12-10 17:00:00,2.4,0.0,-0.0,0.0,1.66,88.65
+2020-12-10 18:00:00,1.63,0.0,-0.0,0.0,1.86,92.05
+2020-12-10 19:00:00,0.66,0.0,-0.0,0.0,2.14,92.0
+2020-12-10 20:00:00,0.11,0.0,-0.0,0.0,2.28,92.0
+2020-12-10 21:00:00,-0.23,0.0,-0.0,0.0,2.41,88.45
+2020-12-10 22:00:00,-0.36,0.0,-0.0,0.0,2.55,88.45
+2020-12-10 23:00:00,-0.28,0.0,-0.0,0.0,2.83,85.1
+2020-12-11 00:00:00,-0.18,0.0,-0.0,0.0,3.24,85.1
+2020-12-11 01:00:00,-0.57,0.0,-0.0,0.0,3.66,81.75
+2020-12-11 02:00:00,-0.6,0.0,-0.0,0.0,3.86,81.75
+2020-12-11 03:00:00,-0.53,0.0,-0.0,0.0,3.86,81.75
+2020-12-11 04:00:00,-0.63,0.0,-0.0,0.0,3.79,81.75
+2020-12-11 05:00:00,-0.76,0.0,-0.0,0.0,3.79,78.6
+2020-12-11 06:00:00,-0.82,0.0,-0.0,0.0,3.86,78.6
+2020-12-11 07:00:00,-0.44,0.0,0.0,0.0,4.21,78.6
+2020-12-11 08:00:00,-0.04,88.0,315.33,48.0,4.21,78.65
+2020-12-11 09:00:00,0.89,129.0,150.76,97.0,4.07,75.75
+2020-12-11 10:00:00,1.83,126.0,45.71,114.0,3.79,70.2
+2020-12-11 11:00:00,2.62,217.0,375.69,114.0,3.93,67.6
+2020-12-11 12:00:00,3.01,227.0,669.55,62.0,3.86,67.7
+2020-12-11 13:00:00,2.95,144.0,452.49,62.0,3.72,67.7
+2020-12-11 14:00:00,2.34,62.0,494.26,21.0,3.79,70.3
+2020-12-11 15:00:00,1.41,0.0,-0.0,0.0,3.72,72.95
+2020-12-11 16:00:00,0.78,0.0,-0.0,0.0,3.66,75.75
+2020-12-11 17:00:00,0.53,0.0,-0.0,0.0,3.66,75.7
+2020-12-11 18:00:00,0.36,0.0,-0.0,0.0,3.52,75.7
+2020-12-11 19:00:00,0.18,0.0,-0.0,0.0,3.59,75.7
+2020-12-11 20:00:00,0.24,0.0,-0.0,0.0,3.31,72.75
+2020-12-11 21:00:00,0.11,0.0,-0.0,0.0,3.1,75.6
+2020-12-11 22:00:00,0.13,0.0,-0.0,0.0,2.9,72.65
+2020-12-11 23:00:00,0.0,0.0,-0.0,0.0,2.83,72.65
+2020-12-12 00:00:00,-0.09,0.0,-0.0,0.0,2.69,72.65
+2020-12-12 01:00:00,-0.17,0.0,-0.0,0.0,2.55,75.6
+2020-12-12 02:00:00,-0.42,0.0,-0.0,0.0,2.55,78.6
+2020-12-12 03:00:00,-0.33,0.0,-0.0,0.0,2.48,78.6
+2020-12-12 04:00:00,0.05,0.0,-0.0,0.0,2.34,78.65
+2020-12-12 05:00:00,0.23,0.0,-0.0,0.0,2.21,78.75
+2020-12-12 06:00:00,0.34,0.0,-0.0,0.0,2.07,81.9
+2020-12-12 07:00:00,0.71,0.0,0.0,0.0,2.0,88.55
+2020-12-12 08:00:00,1.03,51.0,40.05,46.0,1.93,92.05
+2020-12-12 09:00:00,1.62,92.0,33.26,85.0,1.86,92.05
+2020-12-12 10:00:00,2.63,61.0,0.0,61.0,2.07,88.65
+2020-12-12 11:00:00,3.49,125.0,36.65,115.0,2.34,82.25
+2020-12-12 12:00:00,4.18,77.0,4.07,76.0,2.55,79.2
+2020-12-12 13:00:00,4.57,76.0,33.23,70.0,2.07,76.3
+2020-12-12 14:00:00,4.33,54.0,363.37,24.0,1.59,79.3
+2020-12-12 15:00:00,3.45,0.0,-0.0,0.0,1.79,82.25
+2020-12-12 16:00:00,2.66,0.0,-0.0,0.0,2.07,88.65
+2020-12-12 17:00:00,2.36,0.0,-0.0,0.0,2.28,85.35
+2020-12-12 18:00:00,2.08,0.0,-0.0,0.0,2.48,88.65
+2020-12-12 19:00:00,1.24,0.0,-0.0,0.0,2.62,88.6
+2020-12-12 20:00:00,0.78,0.0,-0.0,0.0,2.76,92.05
+2020-12-12 21:00:00,0.83,0.0,-0.0,0.0,2.76,92.05
+2020-12-12 22:00:00,0.62,0.0,-0.0,0.0,2.83,92.0
+2020-12-12 23:00:00,0.52,0.0,-0.0,0.0,2.97,92.0
+2020-12-13 00:00:00,0.4,0.0,-0.0,0.0,3.17,92.0
+2020-12-13 01:00:00,0.15,0.0,-0.0,0.0,3.38,92.0
+2020-12-13 02:00:00,-0.05,0.0,-0.0,0.0,3.52,92.0
+2020-12-13 03:00:00,-0.3,0.0,-0.0,0.0,3.79,88.45
+2020-12-13 04:00:00,-0.41,0.0,-0.0,0.0,4.14,91.95
+2020-12-13 05:00:00,-0.27,0.0,-0.0,0.0,4.34,88.45
+2020-12-13 06:00:00,-0.27,0.0,-0.0,0.0,4.62,88.45
+2020-12-13 07:00:00,-0.22,0.0,0.0,0.0,4.62,88.45
+2020-12-13 08:00:00,-0.06,49.0,32.53,45.0,4.41,88.45
+2020-12-13 09:00:00,0.14,108.0,76.64,92.0,5.1,88.45
+2020-12-13 10:00:00,0.55,143.0,92.49,119.0,5.59,85.15
+2020-12-13 11:00:00,1.36,184.0,217.13,125.0,5.59,75.85
+2020-12-13 12:00:00,1.57,159.0,196.23,111.0,5.31,78.9
+2020-12-13 13:00:00,1.84,50.0,0.0,50.0,4.41,75.95
+2020-12-13 14:00:00,1.72,44.0,170.13,30.0,3.72,75.95
+2020-12-13 15:00:00,1.43,0.0,-0.0,0.0,3.66,78.9
+2020-12-13 16:00:00,1.34,0.0,-0.0,0.0,3.66,78.9
+2020-12-13 17:00:00,1.26,0.0,-0.0,0.0,3.86,78.9
+2020-12-13 18:00:00,1.29,0.0,-0.0,0.0,3.93,82.0
+2020-12-13 19:00:00,2.01,0.0,-0.0,0.0,3.59,85.3
+2020-12-13 20:00:00,2.59,0.0,-0.0,0.0,3.45,85.35
+2020-12-13 21:00:00,3.23,0.0,-0.0,0.0,3.45,82.25
+2020-12-13 22:00:00,3.26,0.0,-0.0,0.0,3.66,82.25
+2020-12-13 23:00:00,3.33,0.0,-0.0,0.0,3.79,82.25
+2020-12-14 00:00:00,3.33,0.0,-0.0,0.0,4.0,82.25
+2020-12-14 01:00:00,3.67,0.0,-0.0,0.0,4.28,88.75
+2020-12-14 02:00:00,3.62,0.0,-0.0,0.0,4.41,92.15
+2020-12-14 03:00:00,3.93,0.0,-0.0,0.0,4.48,88.8
+2020-12-14 04:00:00,4.16,0.0,-0.0,0.0,4.41,88.8
+2020-12-14 05:00:00,4.14,0.0,-0.0,0.0,4.14,85.5
+2020-12-14 06:00:00,3.81,0.0,-0.0,0.0,3.59,85.5
+2020-12-14 07:00:00,3.29,0.0,0.0,0.0,3.66,85.45
+2020-12-14 08:00:00,3.37,33.0,0.0,33.0,3.86,85.45
+2020-12-14 09:00:00,3.68,110.0,91.71,91.0,4.48,85.45
+2020-12-14 10:00:00,3.08,32.0,0.0,32.0,5.03,92.15
+2020-12-14 11:00:00,3.33,22.0,0.0,22.0,5.1,88.75
+2020-12-14 12:00:00,4.81,34.0,0.0,34.0,6.28,88.85
+2020-12-14 13:00:00,4.55,34.0,0.0,34.0,8.14,88.85
+2020-12-14 14:00:00,4.46,52.0,328.69,25.0,6.34,85.55
+2020-12-14 15:00:00,4.57,0.0,-0.0,0.0,5.52,82.35
+2020-12-14 16:00:00,4.38,0.0,-0.0,0.0,5.66,79.3
+2020-12-14 17:00:00,4.2,0.0,-0.0,0.0,5.72,76.25
+2020-12-14 18:00:00,3.96,0.0,-0.0,0.0,5.1,70.6
+2020-12-14 19:00:00,4.17,0.0,-0.0,0.0,4.55,79.2
+2020-12-14 20:00:00,4.58,0.0,-0.0,0.0,5.59,79.3
+2020-12-14 21:00:00,4.97,0.0,-0.0,0.0,6.28,82.35
+2020-12-14 22:00:00,5.15,0.0,-0.0,0.0,6.41,82.35
+2020-12-14 23:00:00,5.1,0.0,-0.0,0.0,6.48,79.3
+2020-12-15 00:00:00,4.67,0.0,-0.0,0.0,6.07,73.45
+2020-12-15 01:00:00,4.22,0.0,-0.0,0.0,4.76,70.7
+2020-12-15 02:00:00,3.6,0.0,-0.0,0.0,3.52,76.15
+2020-12-15 03:00:00,3.09,0.0,-0.0,0.0,2.76,79.1
+2020-12-15 04:00:00,2.81,0.0,-0.0,0.0,2.9,79.1
+2020-12-15 05:00:00,2.88,0.0,-0.0,0.0,3.38,82.2
+2020-12-15 06:00:00,3.49,0.0,-0.0,0.0,4.14,82.25
+2020-12-15 07:00:00,4.76,0.0,0.0,0.0,4.48,88.85
+2020-12-15 08:00:00,5.86,19.0,0.0,19.0,5.24,88.9
+2020-12-15 09:00:00,7.08,41.0,0.0,41.0,5.31,89.0
+2020-12-15 10:00:00,8.48,122.0,46.7,110.0,5.59,85.9
+2020-12-15 11:00:00,10.32,141.0,74.13,121.0,5.72,80.05
+2020-12-15 12:00:00,10.87,83.0,4.11,82.0,5.66,80.1
+2020-12-15 13:00:00,10.37,20.0,0.0,20.0,5.1,83.0
+2020-12-15 14:00:00,9.22,38.0,97.42,30.0,4.14,85.95
+2020-12-15 15:00:00,8.6,0.0,-0.0,0.0,4.0,79.75
+2020-12-15 16:00:00,8.34,0.0,-0.0,0.0,4.07,76.85
+2020-12-15 17:00:00,7.88,0.0,-0.0,0.0,3.93,73.95
+2020-12-15 18:00:00,7.25,0.0,-0.0,0.0,3.79,76.7
+2020-12-15 19:00:00,6.67,0.0,-0.0,0.0,3.72,82.55
+2020-12-15 20:00:00,6.56,0.0,-0.0,0.0,3.79,82.55
+2020-12-15 21:00:00,6.42,0.0,-0.0,0.0,3.72,82.55
+2020-12-15 22:00:00,6.23,0.0,-0.0,0.0,3.52,82.55
+2020-12-15 23:00:00,5.94,0.0,-0.0,0.0,3.24,85.65
+2020-12-16 00:00:00,5.31,0.0,-0.0,0.0,2.9,85.6
+2020-12-16 01:00:00,4.62,0.0,-0.0,0.0,2.55,85.55
+2020-12-16 02:00:00,4.58,0.0,-0.0,0.0,2.34,88.85
+2020-12-16 03:00:00,4.27,0.0,-0.0,0.0,2.28,85.55
+2020-12-16 04:00:00,4.74,0.0,-0.0,0.0,2.34,88.85
+2020-12-16 05:00:00,5.21,0.0,-0.0,0.0,2.48,92.25
+2020-12-16 06:00:00,5.7,0.0,-0.0,0.0,2.62,88.85
+2020-12-16 07:00:00,5.69,0.0,0.0,0.0,2.83,92.25
+2020-12-16 08:00:00,6.38,42.0,16.95,40.0,2.9,88.95
+2020-12-16 09:00:00,7.21,29.0,0.0,29.0,2.83,92.35
+2020-12-16 10:00:00,7.69,162.0,175.84,117.0,2.97,89.0
+2020-12-16 11:00:00,8.31,220.0,457.2,97.0,3.17,85.9
+2020-12-16 12:00:00,8.7,137.0,111.19,110.0,3.52,89.1
+2020-12-16 13:00:00,9.05,93.0,94.91,76.0,3.52,85.95
+2020-12-16 14:00:00,8.69,34.0,60.81,29.0,3.31,85.9
+2020-12-16 15:00:00,7.72,0.0,-0.0,0.0,3.24,89.0
+2020-12-16 16:00:00,7.05,0.0,-0.0,0.0,3.24,89.0
+2020-12-16 17:00:00,6.78,0.0,-0.0,0.0,3.38,89.0
+2020-12-16 18:00:00,6.62,0.0,-0.0,0.0,3.45,88.95
+2020-12-16 19:00:00,6.23,0.0,-0.0,0.0,3.52,92.3
+2020-12-16 20:00:00,5.95,0.0,-0.0,0.0,3.59,92.3
+2020-12-16 21:00:00,5.56,0.0,-0.0,0.0,3.45,92.25
+2020-12-16 22:00:00,5.45,0.0,-0.0,0.0,3.52,92.25
+2020-12-16 23:00:00,5.17,0.0,-0.0,0.0,3.38,95.75
+2020-12-17 00:00:00,5.12,0.0,-0.0,0.0,3.52,92.25
+2020-12-17 01:00:00,5.31,0.0,-0.0,0.0,3.59,88.85
+2020-12-17 02:00:00,5.17,0.0,-0.0,0.0,3.66,92.25
+2020-12-17 03:00:00,5.33,0.0,-0.0,0.0,3.79,88.85
+2020-12-17 04:00:00,5.41,0.0,-0.0,0.0,4.0,85.6
+2020-12-17 05:00:00,5.48,0.0,-0.0,0.0,4.21,85.6
+2020-12-17 06:00:00,5.1,0.0,-0.0,0.0,4.28,88.85
+2020-12-17 07:00:00,4.4,0.0,0.0,0.0,4.34,85.55
+2020-12-17 08:00:00,4.66,72.0,240.27,44.0,4.14,85.55
+2020-12-17 09:00:00,5.35,167.0,521.7,61.0,3.45,85.6
+2020-12-17 10:00:00,6.69,206.0,451.02,91.0,3.52,82.55
+2020-12-17 11:00:00,7.77,161.0,141.59,123.0,3.45,73.95
+2020-12-17 12:00:00,8.64,175.0,309.28,100.0,3.1,74.05
+2020-12-17 13:00:00,9.0,91.0,83.76,76.0,2.97,74.15
+2020-12-17 14:00:00,8.52,52.0,339.63,24.0,2.9,76.85
+2020-12-17 15:00:00,7.22,0.0,-0.0,0.0,3.03,82.6
+2020-12-17 16:00:00,6.42,0.0,-0.0,0.0,3.03,82.55
+2020-12-17 17:00:00,5.66,0.0,-0.0,0.0,3.1,88.85
+2020-12-17 18:00:00,5.25,0.0,-0.0,0.0,3.17,88.85
+2020-12-17 19:00:00,4.88,0.0,-0.0,0.0,3.52,88.85
+2020-12-17 20:00:00,5.08,0.0,-0.0,0.0,3.52,88.85
+2020-12-17 21:00:00,5.62,0.0,-0.0,0.0,3.45,85.6
+2020-12-17 22:00:00,5.88,0.0,-0.0,0.0,3.52,82.5
+2020-12-17 23:00:00,6.1,0.0,-0.0,0.0,3.45,82.5
+2020-12-18 00:00:00,6.03,0.0,-0.0,0.0,3.31,82.5
+2020-12-18 01:00:00,5.82,0.0,-0.0,0.0,3.38,82.5
+2020-12-18 02:00:00,5.77,0.0,-0.0,0.0,3.52,85.65
+2020-12-18 03:00:00,6.42,0.0,-0.0,0.0,3.79,82.55
+2020-12-18 04:00:00,8.03,0.0,-0.0,0.0,3.93,73.95
+2020-12-18 05:00:00,9.11,0.0,-0.0,0.0,3.72,68.8
+2020-12-18 06:00:00,9.5,0.0,-0.0,0.0,3.59,68.9
+2020-12-18 07:00:00,9.49,0.0,-0.0,0.0,3.31,71.5
+2020-12-18 08:00:00,9.63,77.0,329.8,39.0,3.1,77.0
+2020-12-18 09:00:00,9.91,79.0,19.79,75.0,2.83,79.95
+2020-12-18 10:00:00,10.43,75.0,0.0,75.0,2.34,80.05
+2020-12-18 11:00:00,11.39,91.0,3.73,90.0,2.14,77.3
+2020-12-18 12:00:00,11.33,73.0,0.0,73.0,1.79,77.3
+2020-12-18 13:00:00,10.88,80.0,44.65,72.0,1.52,80.1
+2020-12-18 14:00:00,10.51,12.0,0.0,12.0,1.59,83.0
+2020-12-18 15:00:00,10.01,0.0,-0.0,0.0,1.45,86.0
+2020-12-18 16:00:00,9.1,0.0,-0.0,0.0,1.38,92.45
+2020-12-18 17:00:00,8.11,0.0,-0.0,0.0,1.45,95.8
+2020-12-18 18:00:00,6.89,0.0,-0.0,0.0,1.52,95.8
+2020-12-18 19:00:00,4.99,0.0,-0.0,0.0,1.93,99.4
+2020-12-18 20:00:00,4.09,0.0,-0.0,0.0,1.79,95.75
+2020-12-18 21:00:00,3.88,0.0,-0.0,0.0,1.93,95.75
+2020-12-18 22:00:00,4.19,0.0,-0.0,0.0,2.14,95.75
+2020-12-18 23:00:00,4.07,0.0,-0.0,0.0,2.21,95.75
+2020-12-19 00:00:00,4.33,0.0,-0.0,0.0,2.48,95.75
+2020-12-19 01:00:00,4.11,0.0,-0.0,0.0,2.62,95.75
+2020-12-19 02:00:00,4.37,0.0,-0.0,0.0,2.76,95.75
+2020-12-19 03:00:00,4.42,0.0,-0.0,0.0,2.69,95.75
+2020-12-19 04:00:00,4.32,0.0,-0.0,0.0,2.69,95.75
+2020-12-19 05:00:00,4.12,0.0,-0.0,0.0,2.83,95.75
+2020-12-19 06:00:00,4.3,0.0,-0.0,0.0,2.97,95.75
+2020-12-19 07:00:00,4.2,0.0,-0.0,0.0,3.1,95.75
+2020-12-19 08:00:00,4.56,89.0,517.44,30.0,3.52,92.25
+2020-12-19 09:00:00,5.36,157.0,432.55,70.0,3.38,92.25
+2020-12-19 10:00:00,6.39,224.0,607.56,70.0,3.72,92.3
+2020-12-19 11:00:00,6.93,208.0,381.33,106.0,3.93,92.35
+2020-12-19 12:00:00,7.17,139.0,119.73,110.0,4.14,92.35
+2020-12-19 13:00:00,7.15,56.0,5.57,55.0,3.86,92.35
+2020-12-19 14:00:00,6.9,25.0,12.01,24.0,4.0,92.35
+2020-12-19 15:00:00,6.67,0.0,-0.0,0.0,3.86,95.8
+2020-12-19 16:00:00,6.66,0.0,-0.0,0.0,3.79,95.8
+2020-12-19 17:00:00,6.62,0.0,-0.0,0.0,3.72,95.8
+2020-12-19 18:00:00,6.61,0.0,-0.0,0.0,3.72,92.3
+2020-12-19 19:00:00,6.26,0.0,-0.0,0.0,4.07,88.95
+2020-12-19 20:00:00,6.19,0.0,-0.0,0.0,4.14,92.3
+2020-12-19 21:00:00,5.79,0.0,-0.0,0.0,4.07,88.9
+2020-12-19 22:00:00,5.71,0.0,-0.0,0.0,4.07,95.75
+2020-12-19 23:00:00,5.65,0.0,-0.0,0.0,4.14,95.75
+2020-12-20 00:00:00,5.83,0.0,-0.0,0.0,4.14,92.3
+2020-12-20 01:00:00,6.27,0.0,-0.0,0.0,4.28,92.3
+2020-12-20 02:00:00,6.32,0.0,-0.0,0.0,4.34,92.3
+2020-12-20 03:00:00,6.47,0.0,-0.0,0.0,4.41,95.8
+2020-12-20 04:00:00,6.44,0.0,-0.0,0.0,4.34,95.8
+2020-12-20 05:00:00,6.31,0.0,-0.0,0.0,4.41,92.3
+2020-12-20 06:00:00,6.25,0.0,-0.0,0.0,4.55,92.3
+2020-12-20 07:00:00,5.88,0.0,-0.0,0.0,4.97,92.3
+2020-12-20 08:00:00,5.94,83.0,451.55,32.0,4.83,92.3
+2020-12-20 09:00:00,6.61,176.0,639.07,48.0,4.34,92.3
+2020-12-20 10:00:00,7.65,229.0,668.21,60.0,4.55,89.0
+2020-12-20 11:00:00,8.58,245.0,681.06,63.0,4.69,85.9
+2020-12-20 12:00:00,9.08,216.0,643.93,60.0,4.48,82.85
+2020-12-20 13:00:00,9.4,157.0,645.47,41.0,4.41,82.9
+2020-12-20 14:00:00,9.22,41.0,131.2,30.0,4.62,85.95
+2020-12-20 15:00:00,8.53,0.0,-0.0,0.0,4.62,89.1
+2020-12-20 16:00:00,7.99,0.0,-0.0,0.0,4.69,89.05
+2020-12-20 17:00:00,8.04,0.0,-0.0,0.0,4.55,89.05
+2020-12-20 18:00:00,7.87,0.0,-0.0,0.0,4.14,89.05
+2020-12-20 19:00:00,7.3,0.0,-0.0,0.0,3.66,89.0
+2020-12-20 20:00:00,7.02,0.0,-0.0,0.0,3.31,92.35
+2020-12-20 21:00:00,6.86,0.0,-0.0,0.0,2.76,92.35
+2020-12-20 22:00:00,6.65,0.0,-0.0,0.0,2.34,95.8
+2020-12-20 23:00:00,6.79,0.0,-0.0,0.0,2.0,92.35
+2020-12-21 00:00:00,7.07,0.0,-0.0,0.0,2.07,92.35
+2020-12-21 01:00:00,7.95,0.0,-0.0,0.0,2.97,89.05
+2020-12-21 02:00:00,8.38,0.0,-0.0,0.0,3.52,89.1
+2020-12-21 03:00:00,8.32,0.0,-0.0,0.0,3.59,85.9
+2020-12-21 04:00:00,7.97,0.0,-0.0,0.0,3.31,89.05
+2020-12-21 05:00:00,7.32,0.0,-0.0,0.0,2.55,89.0
+2020-12-21 06:00:00,6.42,0.0,-0.0,0.0,2.41,88.95
+2020-12-21 07:00:00,5.79,0.0,-0.0,0.0,2.41,88.9
+2020-12-21 08:00:00,5.25,84.0,473.28,31.0,2.21,92.25
+2020-12-21 09:00:00,6.39,177.0,651.38,47.0,2.28,88.95
+2020-12-21 10:00:00,7.31,233.0,701.03,56.0,2.0,85.8
+2020-12-21 11:00:00,7.96,241.0,647.68,68.0,1.79,82.7
+2020-12-21 12:00:00,8.31,196.0,457.84,85.0,1.38,76.85
+2020-12-21 13:00:00,8.29,129.0,338.55,68.0,1.17,76.85
+2020-12-21 14:00:00,7.62,49.0,236.53,29.0,1.52,82.65
+2020-12-21 15:00:00,6.64,0.0,-0.0,0.0,1.72,88.95
+2020-12-21 16:00:00,5.61,0.0,-0.0,0.0,1.52,92.25
+2020-12-21 17:00:00,4.59,0.0,-0.0,0.0,1.59,92.25
+2020-12-21 18:00:00,4.14,0.0,-0.0,0.0,1.79,95.75
+2020-12-21 19:00:00,4.01,0.0,-0.0,0.0,1.93,95.75
+2020-12-21 20:00:00,3.69,0.0,-0.0,0.0,2.0,99.4
+2020-12-21 21:00:00,3.4,0.0,-0.0,0.0,2.07,95.7
+2020-12-21 22:00:00,3.21,0.0,-0.0,0.0,2.0,95.7
+2020-12-21 23:00:00,3.06,0.0,-0.0,0.0,2.07,99.4
+2020-12-22 00:00:00,2.9,0.0,-0.0,0.0,2.14,99.4
+2020-12-22 01:00:00,3.03,0.0,-0.0,0.0,2.28,99.4
+2020-12-22 02:00:00,3.3,0.0,-0.0,0.0,2.48,95.7
+2020-12-22 03:00:00,3.68,0.0,-0.0,0.0,2.83,99.4
+2020-12-22 04:00:00,3.64,0.0,-0.0,0.0,2.97,95.7
+2020-12-22 05:00:00,3.39,0.0,-0.0,0.0,2.83,95.7
+2020-12-22 06:00:00,3.44,0.0,-0.0,0.0,2.9,95.7
+2020-12-22 07:00:00,3.98,0.0,-0.0,0.0,2.97,95.75
+2020-12-22 08:00:00,4.22,74.0,314.91,39.0,3.03,92.25
+2020-12-22 09:00:00,4.74,110.0,110.56,88.0,3.17,92.25
+2020-12-22 10:00:00,5.45,174.0,249.82,111.0,3.1,88.85
+2020-12-22 11:00:00,6.06,112.0,22.46,106.0,3.03,85.65
+2020-12-22 12:00:00,6.39,166.0,243.04,107.0,2.69,82.55
+2020-12-22 13:00:00,6.4,116.0,221.27,76.0,2.41,82.55
+2020-12-22 14:00:00,6.08,42.0,117.12,32.0,2.34,85.65
+2020-12-22 15:00:00,5.56,0.0,-0.0,0.0,2.48,88.85
+2020-12-22 16:00:00,5.14,0.0,-0.0,0.0,2.48,92.25
+2020-12-22 17:00:00,4.97,0.0,-0.0,0.0,2.48,92.25
+2020-12-22 18:00:00,4.79,0.0,-0.0,0.0,2.41,92.25
+2020-12-22 19:00:00,4.4,0.0,-0.0,0.0,2.55,92.25
+2020-12-22 20:00:00,4.6,0.0,-0.0,0.0,2.28,92.25
+2020-12-22 21:00:00,4.49,0.0,-0.0,0.0,2.14,92.25
+2020-12-22 22:00:00,4.54,0.0,-0.0,0.0,2.0,92.25
+2020-12-22 23:00:00,5.25,0.0,-0.0,0.0,1.93,88.85
+2020-12-23 00:00:00,5.89,0.0,-0.0,0.0,2.34,92.3
+2020-12-23 01:00:00,6.38,0.0,-0.0,0.0,3.03,92.3
+2020-12-23 02:00:00,6.47,0.0,-0.0,0.0,3.45,92.3
+2020-12-23 03:00:00,6.4,0.0,-0.0,0.0,3.79,92.3
+2020-12-23 04:00:00,6.27,0.0,-0.0,0.0,3.93,92.3
+2020-12-23 05:00:00,6.22,0.0,-0.0,0.0,4.07,95.75
+2020-12-23 06:00:00,6.15,0.0,-0.0,0.0,4.48,95.75
+2020-12-23 07:00:00,6.04,0.0,-0.0,0.0,4.76,92.3
+2020-12-23 08:00:00,5.94,24.0,0.0,24.0,4.76,92.3
+2020-12-23 09:00:00,5.88,78.0,20.15,74.0,4.9,92.3
+2020-12-23 10:00:00,5.97,142.0,107.14,115.0,4.83,92.3
+2020-12-23 11:00:00,6.18,113.0,22.45,107.0,5.03,88.9
+2020-12-23 12:00:00,6.37,74.0,0.0,74.0,5.17,85.7
+2020-12-23 13:00:00,6.49,59.0,5.51,58.0,4.76,85.7
+2020-12-23 14:00:00,6.4,22.0,0.0,22.0,4.0,85.7
+2020-12-23 15:00:00,5.89,0.0,-0.0,0.0,3.79,85.65
+2020-12-23 16:00:00,5.64,0.0,-0.0,0.0,3.79,92.25
+2020-12-23 17:00:00,5.47,0.0,-0.0,0.0,4.0,92.25
+2020-12-23 18:00:00,5.4,0.0,-0.0,0.0,4.21,92.25
+2020-12-23 19:00:00,5.14,0.0,-0.0,0.0,4.0,92.25
+2020-12-23 20:00:00,4.95,0.0,-0.0,0.0,4.07,92.25
+2020-12-23 21:00:00,4.9,0.0,-0.0,0.0,4.07,92.25
+2020-12-23 22:00:00,5.03,0.0,-0.0,0.0,4.0,92.25
+2020-12-23 23:00:00,5.09,0.0,-0.0,0.0,4.07,92.25
+2020-12-24 00:00:00,5.18,0.0,-0.0,0.0,4.28,92.25
+2020-12-24 01:00:00,5.36,0.0,-0.0,0.0,4.34,88.85
+2020-12-24 02:00:00,5.38,0.0,-0.0,0.0,4.41,88.85
+2020-12-24 03:00:00,5.32,0.0,-0.0,0.0,4.48,88.85
+2020-12-24 04:00:00,5.23,0.0,-0.0,0.0,4.14,88.85
+2020-12-24 05:00:00,5.06,0.0,-0.0,0.0,3.93,92.25
+2020-12-24 06:00:00,4.96,0.0,-0.0,0.0,3.79,88.85
+2020-12-24 07:00:00,4.96,0.0,-0.0,0.0,3.38,92.25
+2020-12-24 08:00:00,5.02,47.0,54.63,41.0,3.38,92.25
+2020-12-24 09:00:00,5.34,96.0,60.55,84.0,3.38,88.85
+2020-12-24 10:00:00,5.79,197.0,388.94,99.0,2.83,85.65
+2020-12-24 11:00:00,6.45,201.0,332.7,112.0,3.31,79.5
+2020-12-24 12:00:00,6.75,192.0,410.24,92.0,3.31,68.4
+2020-12-24 13:00:00,6.83,120.0,241.32,76.0,2.41,71.05
+2020-12-24 14:00:00,6.68,34.0,45.76,30.0,2.14,73.7
+2020-12-24 15:00:00,6.12,0.0,-0.0,0.0,2.41,76.5
+2020-12-24 16:00:00,5.41,0.0,-0.0,0.0,2.97,79.35
+2020-12-24 17:00:00,4.32,0.0,-0.0,0.0,3.38,88.85
+2020-12-24 18:00:00,3.81,0.0,-0.0,0.0,3.59,92.2
+2020-12-24 19:00:00,4.46,0.0,-0.0,0.0,3.17,92.25
+2020-12-24 20:00:00,5.39,0.0,-0.0,0.0,3.93,92.25
+2020-12-24 21:00:00,6.4,0.0,-0.0,0.0,5.03,88.95
+2020-12-24 22:00:00,6.57,0.0,-0.0,0.0,4.9,88.95
+2020-12-24 23:00:00,6.45,0.0,-0.0,0.0,4.69,88.95
+2020-12-25 00:00:00,6.33,0.0,-0.0,0.0,4.62,92.3
+2020-12-25 01:00:00,6.16,0.0,-0.0,0.0,4.41,95.75
+2020-12-25 02:00:00,6.15,0.0,-0.0,0.0,4.28,92.3
+2020-12-25 03:00:00,6.13,0.0,-0.0,0.0,4.69,92.3
+2020-12-25 04:00:00,5.91,0.0,-0.0,0.0,4.76,92.3
+2020-12-25 05:00:00,5.97,0.0,-0.0,0.0,4.55,92.3
+2020-12-25 06:00:00,5.84,0.0,-0.0,0.0,4.0,92.3
+2020-12-25 07:00:00,5.85,0.0,-0.0,0.0,4.0,95.75
+2020-12-25 08:00:00,5.86,24.0,0.0,24.0,4.0,95.75
+2020-12-25 09:00:00,5.7,91.0,50.51,81.0,3.52,99.4
+2020-12-25 10:00:00,5.42,80.0,3.97,79.0,2.97,95.75
+2020-12-25 11:00:00,5.13,42.0,0.0,42.0,3.17,99.4
+2020-12-25 12:00:00,4.84,41.0,0.0,41.0,2.97,99.4
+2020-12-25 13:00:00,4.63,14.0,0.0,14.0,3.1,95.75
+2020-12-25 14:00:00,4.47,16.0,0.0,16.0,3.1,95.75
+2020-12-25 15:00:00,4.26,0.0,-0.0,0.0,2.76,95.75
+2020-12-25 16:00:00,4.12,0.0,-0.0,0.0,3.24,95.75
+2020-12-25 17:00:00,3.99,0.0,-0.0,0.0,3.31,95.75
+2020-12-25 18:00:00,3.91,0.0,-0.0,0.0,2.83,95.75
+2020-12-25 19:00:00,3.91,0.0,-0.0,0.0,3.45,95.75
+2020-12-25 20:00:00,3.87,0.0,-0.0,0.0,3.52,95.75
+2020-12-25 21:00:00,3.93,0.0,-0.0,0.0,2.55,95.75
+2020-12-25 22:00:00,4.07,0.0,-0.0,0.0,3.1,95.75
+2020-12-25 23:00:00,3.95,0.0,-0.0,0.0,3.66,95.75
+2020-12-26 00:00:00,3.77,0.0,-0.0,0.0,3.93,95.75
+2020-12-26 01:00:00,3.78,0.0,-0.0,0.0,3.52,95.75
+2020-12-26 02:00:00,3.68,0.0,-0.0,0.0,2.62,99.4
+2020-12-26 03:00:00,3.49,0.0,-0.0,0.0,2.48,99.4
+2020-12-26 04:00:00,3.21,0.0,-0.0,0.0,2.21,99.4
+2020-12-26 05:00:00,3.1,0.0,-0.0,0.0,2.07,99.4
+2020-12-26 06:00:00,3.1,0.0,-0.0,0.0,2.21,99.4
+2020-12-26 07:00:00,3.48,0.0,-0.0,0.0,2.41,99.4
+2020-12-26 08:00:00,3.26,53.0,91.74,43.0,2.34,99.4
+2020-12-26 09:00:00,3.53,101.0,75.8,86.0,2.83,99.4
+2020-12-26 10:00:00,4.0,137.0,87.21,115.0,3.86,88.8
+2020-12-26 11:00:00,4.43,119.0,29.8,111.0,3.59,88.85
+2020-12-26 12:00:00,4.93,103.0,24.46,97.0,3.86,85.55
+2020-12-26 13:00:00,4.83,85.0,48.81,76.0,3.31,85.55
+2020-12-26 14:00:00,4.72,38.0,66.74,32.0,2.83,85.55
+2020-12-26 15:00:00,4.01,0.0,-0.0,0.0,2.48,85.5
+2020-12-26 16:00:00,3.24,0.0,-0.0,0.0,2.28,88.75
+2020-12-26 17:00:00,2.53,0.0,-0.0,0.0,2.14,88.65
+2020-12-26 18:00:00,2.44,0.0,-0.0,0.0,2.0,88.65
+2020-12-26 19:00:00,2.67,0.0,-0.0,0.0,2.14,88.65
+2020-12-26 20:00:00,2.63,0.0,-0.0,0.0,2.07,88.65
+2020-12-26 21:00:00,2.52,0.0,-0.0,0.0,2.0,88.65
+2020-12-26 22:00:00,2.59,0.0,-0.0,0.0,1.79,85.35
+2020-12-26 23:00:00,1.99,0.0,-0.0,0.0,1.59,88.65
+2020-12-27 00:00:00,0.95,0.0,-0.0,0.0,1.45,92.05
+2020-12-27 01:00:00,0.02,0.0,-0.0,0.0,1.45,92.0
+2020-12-27 02:00:00,-0.35,0.0,-0.0,0.0,1.45,91.95
+2020-12-27 03:00:00,-0.67,0.0,-0.0,0.0,1.45,88.45
+2020-12-27 04:00:00,-0.29,0.0,-0.0,0.0,1.24,88.45
+2020-12-27 05:00:00,0.29,0.0,-0.0,0.0,1.1,85.15
+2020-12-27 06:00:00,0.38,0.0,-0.0,0.0,1.17,85.15
+2020-12-27 07:00:00,0.03,0.0,-0.0,0.0,1.31,88.45
+2020-12-27 08:00:00,0.44,49.0,64.35,42.0,1.17,88.5
+2020-12-27 09:00:00,1.37,100.0,70.73,86.0,1.31,92.05
+2020-12-27 10:00:00,2.51,102.0,15.83,98.0,2.28,92.15
+2020-12-27 11:00:00,2.99,118.0,26.01,111.0,3.1,85.4
+2020-12-27 12:00:00,2.81,62.0,0.0,62.0,3.38,85.4
+2020-12-27 13:00:00,2.76,51.0,0.0,51.0,3.38,82.2
+2020-12-27 14:00:00,2.69,35.0,43.8,31.0,3.17,85.35
+2020-12-27 15:00:00,2.13,0.0,-0.0,0.0,2.28,92.1
+2020-12-27 16:00:00,1.7,0.0,-0.0,0.0,2.07,92.1
+2020-12-27 17:00:00,1.26,0.0,-0.0,0.0,2.0,95.65
+2020-12-27 18:00:00,1.19,0.0,-0.0,0.0,2.07,95.65
+2020-12-27 19:00:00,1.63,0.0,-0.0,0.0,3.24,95.65
+2020-12-27 20:00:00,1.48,0.0,-0.0,0.0,2.9,99.4
+2020-12-27 21:00:00,1.25,0.0,-0.0,0.0,2.41,99.4
+2020-12-27 22:00:00,1.14,0.0,-0.0,0.0,2.21,99.35
+2020-12-27 23:00:00,1.1,0.0,-0.0,0.0,2.62,99.35
+2020-12-28 00:00:00,0.84,0.0,-0.0,0.0,2.76,95.65
+2020-12-28 01:00:00,0.39,0.0,-0.0,0.0,2.55,99.4
+2020-12-28 02:00:00,0.12,0.0,-0.0,0.0,2.41,99.4
+2020-12-28 03:00:00,-0.1,0.0,-0.0,0.0,2.48,99.4
+2020-12-28 04:00:00,-0.12,0.0,-0.0,0.0,2.76,99.4
+2020-12-28 05:00:00,-0.27,0.0,-0.0,0.0,2.9,95.6
+2020-12-28 06:00:00,-0.37,0.0,-0.0,0.0,2.83,99.4
+2020-12-28 07:00:00,-0.37,0.0,-0.0,0.0,2.62,95.6
+2020-12-28 08:00:00,-0.38,49.0,64.42,42.0,2.55,95.6
+2020-12-28 09:00:00,-0.12,105.0,85.81,88.0,2.62,92.0
+2020-12-28 10:00:00,0.06,124.0,47.42,112.0,2.83,88.45
+2020-12-28 11:00:00,0.65,126.0,37.06,116.0,3.1,78.75
+2020-12-28 12:00:00,0.76,86.0,4.04,85.0,2.83,75.75
+2020-12-28 13:00:00,0.92,53.0,0.0,53.0,2.9,75.75
+2020-12-28 14:00:00,0.74,40.0,64.6,34.0,3.1,75.75
+2020-12-28 15:00:00,0.22,0.0,-0.0,0.0,2.55,81.9
+2020-12-28 16:00:00,-0.37,0.0,-0.0,0.0,2.28,88.45
+2020-12-28 17:00:00,-0.63,0.0,-0.0,0.0,2.07,88.45
+2020-12-28 18:00:00,-1.02,0.0,-0.0,0.0,1.59,88.4
+2020-12-28 19:00:00,-1.03,0.0,-0.0,0.0,1.72,81.7
+2020-12-28 20:00:00,-1.13,0.0,-0.0,0.0,1.45,81.7
+2020-12-28 21:00:00,-1.27,0.0,-0.0,0.0,1.38,81.7
+2020-12-28 22:00:00,-1.65,0.0,-0.0,0.0,1.17,84.95
+2020-12-28 23:00:00,-1.97,0.0,-0.0,0.0,1.03,88.3
+2020-12-29 00:00:00,-1.76,0.0,-0.0,0.0,0.9,84.95
+2020-12-29 01:00:00,-2.16,0.0,-0.0,0.0,0.62,84.85
+2020-12-29 02:00:00,-2.37,0.0,-0.0,0.0,0.9,88.25
+2020-12-29 03:00:00,-1.69,0.0,-0.0,0.0,0.41,78.45
+2020-12-29 04:00:00,-1.76,0.0,-0.0,0.0,0.34,81.65
+2020-12-29 05:00:00,-1.91,0.0,-0.0,0.0,0.28,84.85
+2020-12-29 06:00:00,-1.99,0.0,-0.0,0.0,0.55,84.85
+2020-12-29 07:00:00,-3.95,0.0,-0.0,0.0,1.59,91.75
+2020-12-29 08:00:00,-3.32,77.0,386.44,35.0,1.72,88.25
+2020-12-29 09:00:00,-1.59,168.0,554.44,58.0,1.45,84.95
+2020-12-29 10:00:00,-0.26,240.0,725.31,56.0,1.66,72.65
+2020-12-29 11:00:00,0.59,258.0,734.93,59.0,1.24,69.95
+2020-12-29 12:00:00,1.13,227.0,663.98,62.0,1.31,64.65
+2020-12-29 13:00:00,1.35,161.0,594.51,49.0,1.79,62.25
+2020-12-29 14:00:00,0.78,60.0,296.2,32.0,1.59,67.3
+2020-12-29 15:00:00,-0.02,0.0,-0.0,0.0,1.79,69.85
+2020-12-29 16:00:00,-0.68,0.0,-0.0,0.0,2.07,72.6
+2020-12-29 17:00:00,-0.86,0.0,-0.0,0.0,2.0,72.5
+2020-12-29 18:00:00,-1.05,0.0,-0.0,0.0,2.0,72.5
+2020-12-29 19:00:00,-1.07,0.0,-0.0,0.0,2.21,66.9
+2020-12-29 20:00:00,-1.15,0.0,-0.0,0.0,2.07,69.65
+2020-12-29 21:00:00,-1.1,0.0,-0.0,0.0,2.0,69.65
+2020-12-29 22:00:00,-0.9,0.0,-0.0,0.0,2.07,69.65
+2020-12-29 23:00:00,-0.67,0.0,-0.0,0.0,2.28,67.0
+2020-12-30 00:00:00,-0.5,0.0,-0.0,0.0,2.41,64.35
+2020-12-30 01:00:00,-0.54,0.0,-0.0,0.0,2.55,61.8
+2020-12-30 02:00:00,-0.37,0.0,-0.0,0.0,2.55,61.8
+2020-12-30 03:00:00,-0.15,0.0,-0.0,0.0,2.41,59.45
+2020-12-30 04:00:00,-0.29,0.0,-0.0,0.0,2.41,59.45
+2020-12-30 05:00:00,-0.58,0.0,-0.0,0.0,2.55,59.35
+2020-12-30 06:00:00,-0.24,0.0,-0.0,0.0,2.62,54.8
+2020-12-30 07:00:00,1.03,0.0,-0.0,0.0,2.55,52.85
+2020-12-30 08:00:00,1.35,49.0,73.51,41.0,2.62,53.0
+2020-12-30 09:00:00,2.61,93.0,55.33,82.0,2.55,53.25
+2020-12-30 10:00:00,4.22,166.0,196.53,116.0,2.48,51.7
+2020-12-30 11:00:00,5.75,99.0,7.36,97.0,2.48,49.95
+2020-12-30 12:00:00,6.65,53.0,0.0,53.0,2.76,50.05
+2020-12-30 13:00:00,7.08,108.0,136.87,82.0,2.9,48.25
+2020-12-30 14:00:00,6.49,62.0,332.29,30.0,2.9,46.25
+2020-12-30 15:00:00,5.48,0.0,-0.0,0.0,2.97,46.0
+2020-12-30 16:00:00,4.93,0.0,-0.0,0.0,3.03,45.85
+2020-12-30 17:00:00,5.23,0.0,-0.0,0.0,3.1,44.15
+2020-12-30 18:00:00,5.75,0.0,-0.0,0.0,3.17,40.9
+2020-12-30 19:00:00,5.42,0.0,-0.0,0.0,3.31,42.45
+2020-12-30 20:00:00,5.89,0.0,-0.0,0.0,3.38,40.9
+2020-12-30 21:00:00,6.27,0.0,-0.0,0.0,3.59,39.4
+2020-12-30 22:00:00,6.29,0.0,-0.0,0.0,4.0,39.4
+2020-12-30 23:00:00,6.09,0.0,-0.0,0.0,4.14,39.25
+2020-12-31 00:00:00,6.01,0.0,-0.0,0.0,4.14,39.25
+2020-12-31 01:00:00,5.77,0.0,-0.0,0.0,4.28,37.7
+2020-12-31 02:00:00,5.72,0.0,-0.0,0.0,4.55,36.05
+2020-12-31 03:00:00,5.65,0.0,-0.0,0.0,4.83,34.6
+2020-12-31 04:00:00,5.31,0.0,-0.0,0.0,5.03,33.2
+2020-12-31 05:00:00,4.78,0.0,-0.0,0.0,5.17,35.9
+2020-12-31 06:00:00,4.15,0.0,-0.0,0.0,5.17,42.15
+2020-12-31 07:00:00,4.0,0.0,-0.0,0.0,5.1,51.55
+2020-12-31 08:00:00,3.89,19.0,0.0,19.0,4.76,62.8
+2020-12-31 09:00:00,3.93,21.0,0.0,21.0,4.21,73.4
+2020-12-31 10:00:00,4.33,47.0,0.0,47.0,4.41,79.3
+2020-12-31 11:00:00,4.68,58.0,0.0,58.0,5.45,82.35
+2020-12-31 12:00:00,4.72,42.0,0.0,42.0,4.55,85.55
+2020-12-31 13:00:00,4.87,124.0,219.13,82.0,5.1,79.3
+2020-12-31 14:00:00,4.62,22.0,0.0,22.0,4.0,82.35
+2020-12-31 15:00:00,4.38,0.0,-0.0,0.0,3.79,82.35
+2020-12-31 16:00:00,5.13,0.0,-0.0,0.0,3.61,85.9
+2020-12-31 17:00:00,4.26,0.0,-0.0,0.0,3.52,86.18
+2020-12-31 18:00:00,3.4,0.0,-0.0,0.0,3.42,86.46
+2020-12-31 19:00:00,2.54,0.0,-0.0,0.0,3.33,86.74
+2020-12-31 20:00:00,1.68,0.0,-0.0,0.0,3.24,87.02
+2020-12-31 21:00:00,0.82,0.0,-0.0,0.0,3.15,87.31
+2020-12-31 22:00:00,-0.04,0.0,-0.0,0.0,3.05,87.59
+2020-12-31 23:00:00,-0.91,0.0,-0.0,0.0,2.96,87.87
diff --git a/docs/notebooks/data/tutorial_data.py b/docs/notebooks/data/tutorial_data.py
new file mode 100644
index 000000000..3b4997e0a
--- /dev/null
+++ b/docs/notebooks/data/tutorial_data.py
@@ -0,0 +1,246 @@
+"""Generate tutorial data for notebooks 01-07.
+
+These functions return data (timesteps, profiles, prices) rather than full FlowSystems,
+so notebooks can demonstrate building systems step by step.
+
+Usage:
+ from data.tutorial_data import get_quickstart_data, get_heat_system_data, ...
+"""
+
+import numpy as np
+import pandas as pd
+import xarray as xr
+
+
+def get_quickstart_data() -> dict:
+ """Data for 01-quickstart: minimal 4-hour example.
+
+ Returns:
+ dict with: timesteps, heat_demand (xr.DataArray)
+ """
+ timesteps = pd.date_range('2024-01-15 08:00', periods=4, freq='h')
+ heat_demand = xr.DataArray(
+ [30, 50, 45, 25],
+ dims=['time'],
+ coords={'time': timesteps},
+ name='Heat Demand [kW]',
+ )
+ return {
+ 'timesteps': timesteps,
+ 'heat_demand': heat_demand,
+ }
+
+
+def get_heat_system_data() -> dict:
+ """Data for 02-heat-system: one week with storage.
+
+ Returns:
+ dict with: timesteps, heat_demand, gas_price (arrays)
+ """
+ timesteps = pd.date_range('2024-01-15', periods=168, freq='h')
+ hours = np.arange(168)
+ hour_of_day = hours % 24
+ day_of_week = (hours // 24) % 7
+
+ # Office heat demand pattern
+ base_demand = np.where((hour_of_day >= 7) & (hour_of_day <= 18), 80, 30)
+ weekend_factor = np.where(day_of_week >= 5, 0.5, 1.0)
+ np.random.seed(42)
+ heat_demand = base_demand * weekend_factor + np.random.normal(0, 5, len(timesteps))
+ heat_demand = np.clip(heat_demand, 20, 100)
+
+ # Time-of-use gas prices
+ gas_price = np.where((hour_of_day >= 6) & (hour_of_day <= 22), 0.08, 0.05)
+
+ return {
+ 'timesteps': timesteps,
+ 'heat_demand': heat_demand,
+ 'gas_price': gas_price,
+ }
+
+
+def get_investment_data() -> dict:
+ """Data for 03-investment-optimization: solar pool heating.
+
+ Returns:
+ dict with: timesteps, solar_profile, pool_demand, costs
+ """
+ timesteps = pd.date_range('2024-07-15', periods=168, freq='h')
+ hours = np.arange(168)
+ hour_of_day = hours % 24
+
+ # Solar profile
+ solar_profile = np.maximum(0, np.sin((hour_of_day - 6) * np.pi / 12)) * 0.8
+ solar_profile = np.where((hour_of_day >= 6) & (hour_of_day <= 20), solar_profile, 0)
+ np.random.seed(42)
+ solar_profile = solar_profile * np.random.uniform(0.6, 1.0, len(timesteps))
+
+ # Pool demand
+ pool_demand = np.where((hour_of_day >= 8) & (hour_of_day <= 22), 150, 50)
+
+ return {
+ 'timesteps': timesteps,
+ 'solar_profile': solar_profile,
+ 'pool_demand': pool_demand,
+ 'gas_price': 0.12,
+ 'solar_cost_per_kw_week': 20 / 52,
+ 'tank_cost_per_kwh_week': 1.5 / 52,
+ }
+
+
+def get_constraints_data() -> dict:
+ """Data for 04-operational-constraints: factory steam demand.
+
+ Returns:
+ dict with: timesteps, steam_demand
+ """
+ timesteps = pd.date_range('2024-03-11', periods=72, freq='h')
+ hours = np.arange(72)
+ hour_of_day = hours % 24
+
+ # Shift-based demand
+ steam_demand = np.select(
+ [
+ (hour_of_day >= 6) & (hour_of_day < 14),
+ (hour_of_day >= 14) & (hour_of_day < 22),
+ ],
+ [400, 350],
+ default=80,
+ ).astype(float)
+
+ np.random.seed(123)
+ steam_demand = steam_demand + np.random.normal(0, 20, len(steam_demand))
+ steam_demand = np.clip(steam_demand, 50, 450)
+
+ return {
+ 'timesteps': timesteps,
+ 'steam_demand': steam_demand,
+ }
+
+
+def get_multicarrier_data() -> dict:
+ """Data for 05-multi-carrier-system: hospital CHP.
+
+ Returns:
+ dict with: timesteps, electricity_demand, heat_demand, prices
+ """
+ timesteps = pd.date_range('2024-02-05', periods=168, freq='h')
+ hours = np.arange(168)
+ hour_of_day = hours % 24
+
+ # Electricity demand
+ elec_base = 150
+ elec_daily = 100 * np.sin((hour_of_day - 6) * np.pi / 12)
+ elec_daily = np.maximum(0, elec_daily)
+ electricity_demand = elec_base + elec_daily
+
+ # Heat demand
+ heat_pattern = np.select(
+ [
+ (hour_of_day >= 5) & (hour_of_day < 9),
+ (hour_of_day >= 9) & (hour_of_day < 17),
+ (hour_of_day >= 17) & (hour_of_day < 22),
+ ],
+ [350, 250, 300],
+ default=200,
+ ).astype(float)
+
+ np.random.seed(456)
+ electricity_demand += np.random.normal(0, 15, len(timesteps))
+ heat_demand = heat_pattern + np.random.normal(0, 20, len(timesteps))
+ electricity_demand = np.clip(electricity_demand, 100, 300)
+ heat_demand = np.clip(heat_demand, 150, 400)
+
+ # Prices
+ elec_buy_price = np.where((hour_of_day >= 7) & (hour_of_day <= 21), 0.35, 0.20)
+
+ return {
+ 'timesteps': timesteps,
+ 'electricity_demand': electricity_demand,
+ 'heat_demand': heat_demand,
+ 'elec_buy_price': elec_buy_price,
+ 'elec_sell_price': 0.12,
+ 'gas_price': 0.05,
+ }
+
+
+def get_time_varying_data() -> dict:
+ """Data for 06a-time-varying-parameters: heat pump with variable COP.
+
+ Returns:
+ dict with: timesteps, outdoor_temp, heat_demand, cop
+ """
+ timesteps = pd.date_range('2024-01-22', periods=168, freq='h')
+ hours = np.arange(168)
+ hour_of_day = hours % 24
+
+ # Outdoor temperature
+ temp_base = 2
+ temp_amplitude = 5
+ outdoor_temp = temp_base + temp_amplitude * np.sin((hour_of_day - 6) * np.pi / 12)
+ np.random.seed(789)
+ outdoor_temp = outdoor_temp + np.repeat(np.random.uniform(-3, 3, 7), 24)
+
+ # Heat demand (inversely related to temperature)
+ heat_demand = 200 - 8 * outdoor_temp
+ heat_demand = np.clip(heat_demand, 100, 300)
+
+ # COP calculation
+ t_supply = 45 + 273.15
+ t_source = outdoor_temp + 273.15
+ carnot_cop = t_supply / (t_supply - t_source)
+ cop = np.clip(0.45 * carnot_cop, 2.0, 5.0)
+
+ return {
+ 'timesteps': timesteps,
+ 'outdoor_temp': outdoor_temp,
+ 'heat_demand': heat_demand,
+ 'cop': cop,
+ }
+
+
+def get_scenarios_data() -> dict:
+ """Data for 07-scenarios-and-periods: multi-year planning.
+
+ Returns:
+ dict with: timesteps, periods, scenarios, weights, heat_demand (DataFrame), prices
+ """
+ timesteps = pd.date_range('2024-01-15', periods=168, freq='h')
+ periods = pd.Index([2024, 2025, 2026], name='period')
+ scenarios = pd.Index(['Mild Winter', 'Harsh Winter'], name='scenario')
+ scenario_weights = np.array([0.6, 0.4])
+
+ hours = np.arange(168)
+ hour_of_day = hours % 24
+
+ # Base pattern
+ daily_pattern = np.select(
+ [
+ (hour_of_day >= 6) & (hour_of_day < 9),
+ (hour_of_day >= 9) & (hour_of_day < 17),
+ (hour_of_day >= 17) & (hour_of_day < 22),
+ ],
+ [180, 120, 160],
+ default=100,
+ ).astype(float)
+
+ np.random.seed(42)
+ noise = np.random.normal(0, 10, len(timesteps))
+
+ mild_demand = np.clip(daily_pattern * 0.8 + noise, 60, 200)
+ harsh_demand = np.clip(daily_pattern * 1.3 + noise * 1.5, 100, 280)
+
+ heat_demand = pd.DataFrame(
+ {'Mild Winter': mild_demand, 'Harsh Winter': harsh_demand},
+ index=timesteps,
+ )
+
+ return {
+ 'timesteps': timesteps,
+ 'periods': periods,
+ 'scenarios': scenarios,
+ 'scenario_weights': scenario_weights,
+ 'heat_demand': heat_demand,
+ 'gas_prices': np.array([0.06, 0.08, 0.10]),
+ 'elec_prices': np.array([0.28, 0.34, 0.43]),
+ }
diff --git a/docs/notebooks/fxplot_accessor_demo.ipynb b/docs/notebooks/fxplot_accessor_demo.ipynb
new file mode 100644
index 000000000..db8684d82
--- /dev/null
+++ b/docs/notebooks/fxplot_accessor_demo.ipynb
@@ -0,0 +1,565 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Dataset Plot Accessor Demo (`.fxplot`)\n",
+ "\n",
+ "This notebook demonstrates the new `.fxplot` accessor for `xr.Dataset` objects.\n",
+ "It provides convenient Plotly Express plotting methods with smart auto-faceting and coloring."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import xarray as xr\n",
+ "\n",
+ "import flixopt as fx\n",
+ "\n",
+ "fx.__version__"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import plotly.io as pio\n",
+ "\n",
+ "pio.renderers.default = 'notebook_connected'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Create Sample Data\n",
+ "\n",
+ "Let's create a multi-dimensional dataset to demonstrate the plotting capabilities."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Simple time-series dataset\n",
+ "np.random.seed(42)\n",
+ "time = pd.date_range('2024-01-01', periods=24, freq='h')\n",
+ "\n",
+ "ds_simple = xr.Dataset(\n",
+ " {\n",
+ " 'Solar': (['time'], np.maximum(0, np.sin(np.linspace(0, 2 * np.pi, 24)) * 50 + np.random.randn(24) * 5)),\n",
+ " 'Wind': (['time'], np.abs(np.random.randn(24) * 20 + 30)),\n",
+ " 'Demand': (['time'], np.abs(np.sin(np.linspace(0, 2 * np.pi, 24) + 1) * 40 + 50 + np.random.randn(24) * 5)),\n",
+ " },\n",
+ " coords={'time': time},\n",
+ ")\n",
+ "\n",
+ "ds_simple.to_dataframe().head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Line Plot"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ds_simple.fxplot.line(title='Energy Generation & Demand')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Stacked Bar Chart"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ds_simple[['Solar', 'Wind']].fxplot.stacked_bar(title='Renewable Generation')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Area Chart"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ds_simple[['Solar', 'Wind']].fxplot.area(title='Stacked Area - Generation')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Grouped Bar Chart"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ds_simple.fxplot.bar(title='Grouped Bar Chart')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Heatmap"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create 2D data for heatmap\n",
+ "ds_heatmap = xr.Dataset(\n",
+ " {\n",
+ " 'temperature': (['day', 'hour'], np.random.randn(7, 24) * 5 + 20),\n",
+ " },\n",
+ " coords={\n",
+ " 'day': pd.date_range('2024-01-01', periods=7, freq='D'),\n",
+ " 'hour': range(24),\n",
+ " },\n",
+ ")\n",
+ "\n",
+ "ds_heatmap.fxplot.heatmap('temperature', title='Temperature Heatmap')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Automatic Faceting & Animation\n",
+ "\n",
+ "Extra dimensions are **automatically** assigned to `facet_col`, `facet_row`, and `animation_frame` based on CONFIG priority. Just call the plot method - no configuration needed!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Dataset with scenario AND period dimensions\n",
+ "ds_multi = xr.Dataset(\n",
+ " {\n",
+ " 'Solar': (['time', 'scenario', 'period'], np.random.rand(24, 2, 3) * 50),\n",
+ " 'Wind': (['time', 'scenario', 'period'], np.random.rand(24, 2, 3) * 40 + 20),\n",
+ " },\n",
+ " coords={\n",
+ " 'time': time,\n",
+ " 'scenario': ['base', 'high'],\n",
+ " 'period': ['winter', 'spring', 'summer'],\n",
+ " },\n",
+ ")\n",
+ "\n",
+ "ds_multi.to_dataframe().head()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Just call .line() - dimensions are auto-assigned to facet_col, facet_row, animation_frame\n",
+ "ds_multi.fxplot.line(title='Auto-Faceted: Just Works!')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Same for stacked bar - auto-assigns period to facet_col, scenario to animation\n",
+ "ds_multi.fxplot.stacked_bar(title='Stacked Bar: Also Just Works!')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Same for stacked bar - auto-assigns period to facet_col, scenario to animation\n",
+ "ds_multi.sum('time').fxplot.stacked_bar(title='Stacked Bar: Also Just Works!', x='variable', colors=None)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Customizing Facets & Animation\n",
+ "\n",
+ "Override auto-assignment when needed. Use `None` to disable a slot entirely."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Swap: put scenario in facet_col, period in animation\n",
+ "ds_multi.fxplot.line(facet_col='scenario', animation_frame='period', title='Swapped: Scenario in Columns')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Use both row and column facets - no animation\n",
+ "ds_multi.sum('time').fxplot.area(\n",
+ " facet_col='scenario', facet_row='period', animation_frame=None, title='Grid: Period Γ Scenario'\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Or reduce dimensions with .sel() for a simpler plot\n",
+ "ds_multi.sel(scenario='base', period='summer').fxplot.line(title='Single Slice: No Faceting Needed')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Custom Colors"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Using a colorscale name\n",
+ "ds_simple.fxplot.line(colors='viridis', title='With Viridis Colorscale')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Using explicit color mapping\n",
+ "ds_simple.fxplot.stacked_bar(\n",
+ " colors={'Solar': 'gold', 'Wind': 'skyblue', 'Demand': 'salmon'}, title='With Custom Colors'\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Chaining with Plotly Methods\n",
+ "\n",
+ "Since all methods return `go.Figure`, you can chain Plotly's update methods."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "(\n",
+ " ds_simple.fxplot.line(title='Customized Plot')\n",
+ " .update_layout(xaxis_title='Time of Day', yaxis_title='Power (MW)', legend_title='Source', template='plotly_white')\n",
+ " .update_traces(line_width=2)\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Pre-filtering with xarray\n",
+ "\n",
+ "Filter data using xarray methods before plotting."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Select specific time range\n",
+ "ds_simple.sel(time=slice('2024-01-01 06:00', '2024-01-01 18:00')).fxplot.line(title='Daytime Only')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Select specific variables\n",
+ "ds_simple[['Solar', 'Wind']].fxplot.area(title='Renewables Only')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## DataArray Accessor\n",
+ "\n",
+ "The `.fxplot` accessor also works on `xr.DataArray` objects directly."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Create a DataArray\n",
+ "da = xr.DataArray(\n",
+ " np.random.randn(24, 7) * 5 + 20,\n",
+ " dims=['time', 'day'],\n",
+ " coords={\n",
+ " 'time': pd.date_range('2024-01-01', periods=24, freq='h'),\n",
+ " 'day': pd.date_range('2024-01-01', periods=7, freq='D'),\n",
+ " },\n",
+ " name='temperature',\n",
+ ")\n",
+ "\n",
+ "# Heatmap directly from DataArray\n",
+ "da.fxplot.heatmap(title='DataArray Heatmap')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Line plot from DataArray (converts to Dataset internally)\n",
+ "da_1d = xr.DataArray(\n",
+ " np.sin(np.linspace(0, 4 * np.pi, 100)) * 50,\n",
+ " dims=['time'],\n",
+ " coords={'time': pd.date_range('2024-01-01', periods=100, freq='h')},\n",
+ " name='signal',\n",
+ ")\n",
+ "da_1d.fxplot.line(title='DataArray Line Plot')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Axis Labels\n",
+ "\n",
+ "Use `xlabel` and `ylabel` parameters to customize axis labels."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "ds_simple.fxplot.line(title='Generation with Custom Axis Labels', xlabel='Time of Day', ylabel='Power [MW]')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Scatter Plot\n",
+ "\n",
+ "Plot two variables against each other."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Basic scatter plot\n",
+ "ds_simple.fxplot.scatter(\n",
+ " x='Solar', y='Demand', title='Solar vs Demand Correlation', xlabel='Solar Generation [MW]', ylabel='Demand [MW]'\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Scatter with faceting by period, for one scenario\n",
+ "ds_multi.sel(scenario='high').fxplot.scatter(\n",
+ " x='Solar', y='Wind', facet_col='period', title='Solar vs Wind by Period (High Scenario)'\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Pie Chart\n",
+ "\n",
+ "Aggregate data to at most 1D per variable. Scalar data creates a single pie; 1D data creates faceted pies."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Single pie from scalar values (sum over time)\n",
+ "ds_simple[['Solar', 'Wind']].sum('time').fxplot.pie(\n",
+ " title='Total Generation by Source', colors={'Solar': 'gold', 'Wind': 'skyblue'}\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Faceted pie - auto-assigns scenario and period to facets\n",
+ "ds_multi.sum('time').fxplot.pie(\n",
+ " title='Generation by Source (Scenario Γ Period)',\n",
+ " colors={'Solar': 'gold', 'Wind': 'skyblue'},\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Duration Curve\n",
+ "\n",
+ "Use `.fxstats.to_duration_curve()` to transform data, then `.fxplot.line()` to plot. Clean separation of transformation and plotting."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Duration curve with normalized x-axis (percentage)\n",
+ "ds_simple.fxstats.to_duration_curve().fxplot.line(title='Duration Curves', xlabel='Duration [%]')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Duration curve with absolute timesteps\n",
+ "ds_simple.fxstats.to_duration_curve(normalize=False).fxplot.line(title='Duration Curves', xlabel='Timesteps')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Duration curve with auto-faceting - works seamlessly!\n",
+ "ds_multi.fxstats.to_duration_curve().fxplot.line(title='Duration Curves (Auto-Faceted)', xlabel='Duration [%]')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Line Shape Configuration\n",
+ "\n",
+ "The default line shape is controlled by `CONFIG.Plotting.default_line_shape` (default: `'hv'` for step plots).\n",
+ "Override per-plot with the `line_shape` parameter. Options: `'linear'`, `'hv'`, `'vh'`, `'hvh'`, `'vhv'`, `'spline'`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Default step plot (hv)\n",
+ "ds_simple[['Solar']].fxplot.line(title='Default Step Plot (hv)')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Override to linear interpolation\n",
+ "ds_simple[['Solar']].fxplot.line(line_shape='linear', title='Linear Interpolation')"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.11"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/docs/user-guide/optimization/clustering.md b/docs/user-guide/optimization/clustering.md
new file mode 100644
index 000000000..793fbf8fe
--- /dev/null
+++ b/docs/user-guide/optimization/clustering.md
@@ -0,0 +1,264 @@
+# Time-Series Clustering
+
+Time-series clustering reduces large optimization problems by aggregating timesteps into representative **typical periods**. This enables fast investment optimization while preserving key system dynamics.
+
+## When to Use Clustering
+
+Use clustering when:
+
+- Optimizing over a **full year** or longer
+- **Investment sizing** is the primary goal (not detailed dispatch)
+- You need **faster solve times** and can accept approximation
+- The system has **repeating patterns** (daily, weekly, seasonal)
+
+**Skip clustering** for:
+
+- Short optimization horizons (days to weeks)
+- Dispatch-only problems without investments
+- Systems requiring exact temporal sequences
+
+## Two-Stage Workflow
+
+The recommended approach: cluster for fast sizing, then validate at full resolution.
+
+```python
+import flixopt as fx
+
+# Load or create your FlowSystem
+flow_system = fx.FlowSystem(timesteps)
+flow_system.add_elements(...)
+
+# Stage 1: Cluster and optimize (fast)
+fs_clustered = flow_system.transform.cluster(
+ n_clusters=12,
+ cluster_duration='1D',
+ time_series_for_high_peaks=['HeatDemand(Q)|fixed_relative_profile'],
+)
+fs_clustered.optimize(fx.solvers.HighsSolver())
+
+# Stage 2: Expand back to full resolution
+fs_expanded = fs_clustered.transform.expand_solution()
+
+# Access full-resolution results
+charge_state = fs_expanded.solution['Storage|charge_state']
+flow_rates = fs_expanded.solution['Boiler(Q_th)|flow_rate']
+```
+
+## Clustering Parameters
+
+| Parameter | Description | Example |
+|-----------|-------------|---------|
+| `n_clusters` | Number of typical periods | `12` (typical days for a year) |
+| `cluster_duration` | Duration of each cluster | `'1D'`, `'24h'`, or `24` (hours) |
+| `time_series_for_high_peaks` | Time series where peak clusters must be captured | `['HeatDemand(Q)|fixed_relative_profile']` |
+| `time_series_for_low_peaks` | Time series where minimum clusters must be captured | `['SolarGen(P)|fixed_relative_profile']` |
+| `cluster_method` | Clustering algorithm | `'k_means'`, `'hierarchical'`, `'k_medoids'` |
+| `representation_method` | How clusters are represented | `'meanRepresentation'`, `'medoidRepresentation'` |
+| `random_state` | Random seed for reproducibility | `42` |
+| `rescale_cluster_periods` | Rescale clusters to match original means | `True` (default) |
+
+### Peak Selection
+
+Use `time_series_for_high_peaks` to ensure extreme conditions are represented:
+
+```python
+# Ensure the peak demand day is included
+fs_clustered = flow_system.transform.cluster(
+ n_clusters=8,
+ cluster_duration='1D',
+ time_series_for_high_peaks=['HeatDemand(Q)|fixed_relative_profile'],
+)
+```
+
+Without peak selection, the clustering algorithm might average out extreme days, leading to undersized equipment.
+
+### Advanced Clustering Options
+
+Fine-tune the clustering algorithm with advanced parameters:
+
+```python
+fs_clustered = flow_system.transform.cluster(
+ n_clusters=8,
+ cluster_duration='1D',
+ cluster_method='hierarchical', # Alternative to k_means
+ representation_method='medoidRepresentation', # Use actual periods, not averages
+ rescale_cluster_periods=True, # Match original time series means
+ random_state=42, # Reproducible results
+)
+```
+
+**Available clustering algorithms** (`cluster_method`):
+
+| Method | Description |
+|--------|-------------|
+| `'k_means'` | Fast, good for most cases (default) |
+| `'hierarchical'` | Produces consistent hierarchical groupings |
+| `'k_medoids'` | Uses actual periods as representatives |
+| `'k_maxoids'` | Maximizes representativeness |
+| `'averaging'` | Simple averaging of similar periods |
+
+For advanced tsam parameters not exposed directly, use `**kwargs`:
+
+```python
+# Pass any tsam.TimeSeriesAggregation parameter
+fs_clustered = flow_system.transform.cluster(
+ n_clusters=8,
+ cluster_duration='1D',
+ sameMean=True, # Normalize all time series to same mean
+ sortValues=True, # Cluster by duration curves instead of shape
+)
+```
+
+### Clustering Quality Metrics
+
+After clustering, access quality metrics to evaluate the aggregation accuracy:
+
+```python
+fs_clustered = flow_system.transform.cluster(n_clusters=8, cluster_duration='1D')
+
+# Access clustering metrics (xr.Dataset)
+metrics = fs_clustered.clustering.metrics
+print(metrics) # Shows RMSE, MAE, etc. per time series
+
+# Access specific metric
+rmse = metrics['RMSE'] # xr.DataArray with dims [time_series, period?, scenario?]
+```
+
+## Storage Modes
+
+Storage behavior during clustering is controlled via the `cluster_mode` parameter:
+
+```python
+storage = fx.Storage(
+ 'SeasonalPit',
+ capacity_in_flow_hours=5000,
+ cluster_mode='intercluster_cyclic', # Default
+ ...
+)
+```
+
+### Available Modes
+
+| Mode | Behavior | Best For |
+|------|----------|----------|
+| `'intercluster_cyclic'` | Links storage across clusters + yearly cycling | Seasonal storage (pit, underground) |
+| `'intercluster'` | Links storage across clusters, free start/end | Multi-year optimization |
+| `'cyclic'` | Each cluster independent, but start = end | Daily storage (battery, hot water tank) |
+| `'independent'` | Each cluster fully independent | Quick estimates, debugging |
+
+### How Inter-Cluster Linking Works
+
+For `'intercluster'` and `'intercluster_cyclic'` modes, the optimizer tracks:
+
+1. **`SOC_boundary`**: Absolute state-of-charge at the start of each original period
+2. **`charge_state`**: Relative change (ΞE) within each typical period
+
+During expansion, these combine with self-discharge decay:
+
+```
+actual_SOC(t) = SOC_boundary[period] Γ (1 - loss)^t + ΞE(t)
+```
+
+This enables accurate modeling of seasonal storage that charges in summer and discharges in winter.
+
+### Choosing the Right Mode
+
+```python
+# Seasonal pit storage - needs yearly linking
+pit_storage = fx.Storage(
+ 'SeasonalPit',
+ cluster_mode='intercluster_cyclic',
+ capacity_in_flow_hours=10000,
+ relative_loss_per_hour=0.0001,
+ ...
+)
+
+# Daily hot water tank - only needs daily cycling
+tank = fx.Storage(
+ 'HotWaterTank',
+ cluster_mode='cyclic',
+ capacity_in_flow_hours=50,
+ ...
+)
+
+# Battery with quick estimate
+battery = fx.Storage(
+ 'Battery',
+ cluster_mode='independent', # Fastest, ignores long-term effects
+ ...
+)
+```
+
+## Multi-Dimensional Support
+
+Clustering works with periods and scenarios:
+
+```python
+# FlowSystem with multiple periods and scenarios
+flow_system = fx.FlowSystem(
+ timesteps,
+ periods=pd.Index([2025, 2030, 2035], name='period'),
+ scenarios=pd.Index(['low', 'base', 'high'], name='scenario'),
+)
+
+# Cluster - dimensions are preserved
+fs_clustered = flow_system.transform.cluster(
+ n_clusters=8,
+ cluster_duration='1D',
+)
+
+# Solution has all dimensions
+# Dims: (time, cluster, period, scenario)
+flow_rate = fs_clustered.solution['Boiler(Q_th)|flow_rate']
+```
+
+## Expanding Solutions
+
+After optimization, expand results back to full resolution:
+
+```python
+fs_expanded = fs_clustered.transform.expand_solution()
+
+# Full timesteps are restored
+print(f"Original: {len(flow_system.timesteps)} timesteps")
+print(f"Clustered: {len(fs_clustered.timesteps)} timesteps")
+print(f"Expanded: {len(fs_expanded.timesteps)} timesteps")
+
+# Storage charge state correctly reconstructed
+charge_state = fs_expanded.solution['Storage|charge_state']
+```
+
+The expansion:
+
+1. Maps each original timestep to its assigned cluster
+2. For storage with inter-cluster linking, combines `SOC_boundary` with within-cluster `charge_state`
+3. Applies self-discharge decay factors
+
+## Performance Tips
+
+### Cluster Count Selection
+
+| Time Horizon | Cluster Duration | Suggested n_clusters |
+|----------------|------------------|---------------------|
+| 1 year | 1 day | 8-16 |
+| 1 year | 1 week | 4-8 |
+| Multiple years | 1 day | 12-24 |
+
+### Speed vs Accuracy Trade-off
+
+```python
+# Fast (less accurate) - for quick estimates
+fs_fast = flow_system.transform.cluster(n_clusters=4, cluster_duration='1D')
+
+# Balanced - typical production use
+fs_balanced = flow_system.transform.cluster(n_clusters=12, cluster_duration='1D')
+
+# Accurate (slower) - for final results
+fs_accurate = flow_system.transform.cluster(n_clusters=24, cluster_duration='1D')
+```
+
+## See Also
+
+- [Storage Component](../mathematical-notation/elements/Storage.md) - Storage mathematical formulation
+- [Notebooks: Clustering](../../notebooks/08c-clustering.ipynb) - Interactive examples
+- [Notebooks: Storage Modes](../../notebooks/08c2-clustering-storage-modes.ipynb) - Storage mode comparison
diff --git a/docs/user-guide/optimization/index.md b/docs/user-guide/optimization/index.md
index 1d36eb9ba..103ff12ea 100644
--- a/docs/user-guide/optimization/index.md
+++ b/docs/user-guide/optimization/index.md
@@ -56,22 +56,18 @@ flow_system.solve(fx.solvers.HighsSolver())
For large problems, use time series clustering to reduce computational complexity:
```python
-# Define clustering parameters
-params = fx.ClusteringParameters(
- hours_per_period=24, # Hours per typical period
- nr_of_periods=8, # Number of typical periods
- fix_storage_flows=True,
- aggregate_data_and_fix_non_binary_vars=True,
+# Cluster to 12 typical days
+fs_clustered = flow_system.transform.cluster(
+ n_clusters=12,
+ cluster_duration='1D',
+ time_series_for_high_peaks=['HeatDemand(Q)|fixed_relative_profile'],
)
-# Create clustered FlowSystem
-clustered_fs = flow_system.transform.cluster(params)
-
# Optimize the clustered system
-clustered_fs.optimize(fx.solvers.HighsSolver())
+fs_clustered.optimize(fx.solvers.HighsSolver())
-# Access results - same structure as original
-print(clustered_fs.solution)
+# Expand back to full resolution
+fs_expanded = fs_clustered.transform.expand_solution()
```
**Best for:**
@@ -86,6 +82,8 @@ print(clustered_fs.solution)
- Approximates the full problem
- Best when patterns repeat (e.g., typical days)
+See the **[Clustering Guide](clustering.md)** for details on storage modes, peak selection, and multi-dimensional support.
+
## Choosing an Optimization Mode
| Mode | Problem Size | Solve Time | Solution Quality |
@@ -133,7 +131,7 @@ fs_4h.optimize(fx.solvers.HighsSolver())
### Clustering
-See [Clustered Optimization](#clustered-optimization) above.
+See the **[Clustering Guide](clustering.md)** for comprehensive documentation.
### Use Cases
diff --git a/docs/user-guide/recipes/plotting-custom-data.md b/docs/user-guide/recipes/plotting-custom-data.md
index 3c539e6ce..8c19931f3 100644
--- a/docs/user-guide/recipes/plotting-custom-data.md
+++ b/docs/user-guide/recipes/plotting-custom-data.md
@@ -1,125 +1,30 @@
# Plotting Custom Data
-The plot accessor (`flow_system.statistics.plot`) is designed for visualizing optimization results using element labels. If you want to create faceted plots with your own custom data (not from a FlowSystem), you can use Plotly Express directly with xarray data.
+While the plot accessor (`flow_system.statistics.plot`) is designed for optimization results, you often need to plot custom xarray data. The `.fxplot` accessor provides the same convenience for any `xr.Dataset` or `xr.DataArray`.
-## Faceted Plots with Custom xarray Data
-
-The key is converting your xarray Dataset to a long-form DataFrame that Plotly Express expects:
+## Quick Example
```python
+import flixopt as fx
import xarray as xr
-import pandas as pd
-import plotly.express as px
-# Your custom xarray Dataset
-my_data = xr.Dataset({
- 'Solar': (['time', 'scenario'], solar_values),
- 'Wind': (['time', 'scenario'], wind_values),
- 'Demand': (['time', 'scenario'], demand_values),
-}, coords={
- 'time': timestamps,
- 'scenario': ['Base', 'High RE', 'Low Demand']
+ds = xr.Dataset({
+ 'Solar': (['time'], solar_values),
+ 'Wind': (['time'], wind_values),
})
-# Convert to long-form DataFrame for Plotly Express
-df = (
- my_data
- .to_dataframe()
- .reset_index()
- .melt(
- id_vars=['time', 'scenario'], # Keep as columns
- var_name='variable',
- value_name='value'
- )
-)
-
-# Faceted stacked bar chart
-fig = px.bar(
- df,
- x='time',
- y='value',
- color='variable',
- facet_col='scenario',
- barmode='relative',
- title='Energy Balance by Scenario'
-)
-fig.show()
-
-# Faceted line plot
-fig = px.line(
- df,
- x='time',
- y='value',
- color='variable',
- facet_col='scenario'
-)
-fig.show()
-
-# Faceted area chart
-fig = px.area(
- df,
- x='time',
- y='value',
- color='variable',
- facet_col='scenario'
-)
-fig.show()
-```
-
-## Common Plotly Express Faceting Options
-
-| Parameter | Description |
-|-----------|-------------|
-| `facet_col` | Dimension for column subplots |
-| `facet_row` | Dimension for row subplots |
-| `animation_frame` | Dimension for animation slider |
-| `facet_col_wrap` | Number of columns before wrapping |
-
-```python
-# Row and column facets
-fig = px.line(df, x='time', y='value', color='variable',
- facet_col='scenario', facet_row='region')
-
-# Animation over time periods
-fig = px.bar(df, x='variable', y='value', color='variable',
- animation_frame='period', barmode='group')
-
-# Wrap columns
-fig = px.line(df, x='time', y='value', color='variable',
- facet_col='scenario', facet_col_wrap=2)
+# Plot directly - no conversion needed!
+ds.fxplot.line(title='Energy Generation')
+ds.fxplot.stacked_bar(title='Stacked Generation')
```
-## Heatmaps with Custom Data
-
-For heatmaps, you can pass 2D arrays directly to `px.imshow`:
-
-```python
-import plotly.express as px
-
-# 2D data (e.g., days Γ hours)
-heatmap_data = my_data['Solar'].sel(scenario='Base').values.reshape(365, 24)
+## Full Documentation
-fig = px.imshow(
- heatmap_data,
- labels={'x': 'Hour', 'y': 'Day', 'color': 'Power [kW]'},
- aspect='auto',
- color_continuous_scale='portland'
-)
-fig.show()
-
-# Faceted heatmaps using subplots
-from plotly.subplots import make_subplots
-import plotly.graph_objects as go
-
-scenarios = ['Base', 'High RE']
-fig = make_subplots(rows=1, cols=len(scenarios), subplot_titles=scenarios)
-
-for i, scenario in enumerate(scenarios, 1):
- data = my_data['Solar'].sel(scenario=scenario).values.reshape(365, 24)
- fig.add_trace(go.Heatmap(z=data, colorscale='portland'), row=1, col=i)
-
-fig.update_layout(title='Solar Output by Scenario')
-fig.show()
-```
+For comprehensive documentation with interactive examples, see the [Custom Data Plotting](../../notebooks/fxplot_accessor_demo.ipynb) notebook which covers:
-This approach gives you full control over your visualizations while leveraging Plotly's powerful faceting capabilities.
+- All available plot methods (line, bar, stacked_bar, area, scatter, heatmap, pie)
+- Automatic x-axis selection and faceting
+- Custom colors and axis labels
+- Duration curves with `.fxstats.to_duration_curve()`
+- Configuration options
+- Combining with xarray operations
diff --git a/docs/user-guide/results-plotting.md b/docs/user-guide/results-plotting.md
index 1ecd26aa1..28e3d2b2b 100644
--- a/docs/user-guide/results-plotting.md
+++ b/docs/user-guide/results-plotting.md
@@ -2,6 +2,9 @@
After solving an optimization, flixOpt provides a powerful plotting API to visualize and analyze your results. The API is designed to be intuitive and chainable, giving you quick access to common plots while still allowing deep customization.
+!!! tip "Plotting Custom Data"
+ For plotting arbitrary xarray data (not just flixopt results), see the [Custom Data Plotting](recipes/plotting-custom-data.md) guide which covers the `.fxplot` accessor.
+
## The Plot Accessor
All plotting is accessed through the `statistics.plot` accessor on your FlowSystem:
diff --git a/docs/user-guide/results/index.md b/docs/user-guide/results/index.md
index a9b40f7f9..500a64cd9 100644
--- a/docs/user-guide/results/index.md
+++ b/docs/user-guide/results/index.md
@@ -277,6 +277,156 @@ flow_system.statistics.plot.heatmap('Boiler(Q_th)|flow_rate')
flow_system.to_netcdf('results/optimized_system.nc')
```
+## Comparing Multiple Systems
+
+Use the [`Comparison`][flixopt.comparison.Comparison] class to analyze and visualize multiple FlowSystems side-by-side. This is useful for:
+
+- Comparing different design alternatives (with/without CHP, different storage sizes)
+- Analyzing optimization method trade-offs (full vs. two-stage, different aggregation levels)
+- Sensitivity analysis (different scenarios, parameter variations)
+
+### Basic Usage
+
+```python
+import flixopt as fx
+
+# Optimize two system variants
+fs_baseline = create_system()
+fs_baseline.name = 'Baseline'
+fs_baseline.optimize(solver)
+
+fs_with_storage = create_system_with_storage()
+fs_with_storage.name = 'With Storage'
+fs_with_storage.optimize(solver)
+
+# Create comparison
+comp = fx.Comparison([fs_baseline, fs_with_storage])
+
+# Side-by-side balance plots (auto-faceted by 'case' dimension)
+comp.statistics.plot.balance('Heat')
+
+# Access combined data with 'case' dimension
+comp.statistics.flow_rates # xr.Dataset with dims: (time, case)
+comp.solution # Combined solution dataset
+```
+
+### Requirements
+
+All FlowSystems must have **matching core dimensions** (`time`, `period`, `scenario`). Auxiliary dimensions like `cluster_boundary` are ignored. If core dimensions differ, use `.transform.sel()` to align them first:
+
+```python
+# Systems with different scenarios
+fs_both = flow_system # Has 'Mild Winter' and 'Harsh Winter' scenarios
+fs_mild = flow_system.transform.sel(scenario='Mild Winter') # Single scenario
+
+# Cannot compare directly - scenario dimension mismatch!
+# fx.Comparison([fs_both, fs_mild]) # Raises ValueError
+
+# Instead, select matching dimensions
+fs_both_mild = fs_both.transform.sel(scenario='Mild Winter')
+comp = fx.Comparison([fs_both_mild, fs_mild]) # Works!
+
+# Auxiliary dimensions are OK (e.g., expanded clustered solutions)
+fs_expanded = fs_clustered.transform.expand_solution() # Has cluster_boundary dim
+comp = fx.Comparison([fs_full, fs_expanded]) # Works! cluster_boundary is ignored
+```
+
+### Available Properties
+
+The `Comparison.statistics` accessor mirrors all `StatisticsAccessor` properties, returning combined datasets with an added `'case'` dimension:
+
+| Property | Description |
+|----------|-------------|
+| `flow_rates` | All flow rate variables |
+| `flow_hours` | Flow hours (energy) |
+| `sizes` | Component sizes |
+| `storage_sizes` | Storage capacities |
+| `charge_states` | Storage charge states |
+| `temporal_effects` | Effects per timestep |
+| `periodic_effects` | Investment effects |
+| `total_effects` | Combined effects |
+
+### Available Plot Methods
+
+All standard plot methods work on the comparison, with the `'case'` dimension automatically used for faceting:
+
+```python
+comp = fx.Comparison([fs_baseline, fs_modified])
+
+# Balance plots - faceted by case
+comp.statistics.plot.balance('Heat')
+comp.statistics.plot.balance('Electricity', mode='area')
+
+# Flow plots
+comp.statistics.plot.flows(component='CHP')
+
+# Effect breakdowns
+comp.statistics.plot.effects()
+
+# Heatmaps
+comp.statistics.plot.heatmap('Boiler(Q_th)')
+
+# Duration curves
+comp.statistics.plot.duration_curve('CHP(Q_th)')
+
+# Storage plots
+comp.statistics.plot.storage('Battery')
+```
+
+### Computing Differences
+
+Use the `diff()` method to compute differences relative to a reference case:
+
+```python
+# Differences relative to first case (default)
+differences = comp.diff()
+
+# Differences relative to specific case
+differences = comp.diff(reference='Baseline')
+differences = comp.diff(reference=0) # By index
+
+# Analyze differences
+print(differences['costs']) # Cost difference per case
+```
+
+### Naming Systems
+
+System names come from `FlowSystem.name` by default. Override with the `names` parameter:
+
+```python
+# Using FlowSystem.name (default)
+fs1.name = 'Scenario A'
+fs2.name = 'Scenario B'
+comp = fx.Comparison([fs1, fs2])
+
+# Or override explicitly
+comp = fx.Comparison([fs1, fs2], names=['Base Case', 'Alternative'])
+```
+
+### Example: Comparing Optimization Methods
+
+```python
+# Full optimization
+fs_full = flow_system.copy()
+fs_full.name = 'Full Optimization'
+fs_full.optimize(solver)
+
+# Two-stage optimization
+fs_sizing = flow_system.transform.resample('4h')
+fs_sizing.optimize(solver)
+fs_dispatch = flow_system.transform.fix_sizes(fs_sizing.statistics.sizes)
+fs_dispatch.name = 'Two-Stage'
+fs_dispatch.optimize(solver)
+
+# Compare results
+comp = fx.Comparison([fs_full, fs_dispatch])
+comp.statistics.plot.balance('Heat')
+
+# Check cost difference
+diff = comp.diff()
+print(f"Cost difference: {diff['costs'].sel(case='Two-Stage').item():.0f} β¬")
+```
+
## Next Steps
- [Plotting Results](../results-plotting.md) - Detailed plotting documentation
diff --git a/flixopt/__init__.py b/flixopt/__init__.py
index 1e3fee5bd..b84b82a4f 100644
--- a/flixopt/__init__.py
+++ b/flixopt/__init__.py
@@ -3,7 +3,6 @@
"""
import logging
-import warnings
from importlib.metadata import PackageNotFoundError, version
try:
@@ -13,9 +12,12 @@
__version__ = '0.0.0.dev0'
# Import commonly used classes and functions
-from . import linear_converters, plotting, results, solvers
+from . import clustering, linear_converters, plotting, results, solvers
+
+# Register xr.Dataset.fxplot accessor (import triggers registration via decorator)
+from . import dataset_plot_accessor as _ # noqa: F401
from .carrier import Carrier, CarrierContainer
-from .clustering import ClusteringParameters
+from .comparison import Comparison
from .components import (
LinearConverter,
Sink,
@@ -30,7 +32,7 @@
from .elements import Bus, Flow
from .flow_system import FlowSystem
from .interface import InvestParameters, Piece, Piecewise, PiecewiseConversion, PiecewiseEffects, StatusParameters
-from .optimization import ClusteredOptimization, Optimization, SegmentedOptimization
+from .optimization import Optimization, SegmentedOptimization
from .plot_result import PlotResult
__all__ = [
@@ -38,6 +40,7 @@
'CONFIG',
'Carrier',
'CarrierContainer',
+ 'Comparison',
'Flow',
'Bus',
'Effect',
@@ -50,7 +53,6 @@
'Transmission',
'FlowSystem',
'Optimization',
- 'ClusteredOptimization',
'SegmentedOptimization',
'InvestParameters',
'StatusParameters',
@@ -58,47 +60,15 @@
'Piecewise',
'PiecewiseConversion',
'PiecewiseEffects',
- 'ClusteringParameters',
'PlotResult',
+ 'clustering',
'plotting',
'results',
'linear_converters',
'solvers',
]
-# Initialize logger with default configuration (silent: WARNING level, NullHandler)
+# Initialize logger with default configuration (silent: WARNING level, NullHandler).
logger = logging.getLogger('flixopt')
logger.setLevel(logging.WARNING)
logger.addHandler(logging.NullHandler())
-
-# === Runtime warning suppression for third-party libraries ===
-# These warnings are from dependencies and cannot be fixed by end users.
-# They are suppressed at runtime to provide a cleaner user experience.
-# These filters match the test configuration in pyproject.toml for consistency.
-
-# tsam: Time series aggregation library
-# - UserWarning: Informational message about minimal value constraints during clustering.
-warnings.filterwarnings(
- 'ignore',
- category=UserWarning,
- message='.*minimal value.*exceeds.*',
- module='tsam.timeseriesaggregation', # More specific if possible
-)
-# TODO: Might be able to fix it in flixopt?
-
-# linopy: Linear optimization library
-# - UserWarning: Coordinate mismatch warnings that don't affect functionality and are expected.
-warnings.filterwarnings(
- 'ignore', category=UserWarning, message='Coordinates across variables not equal', module='linopy'
-)
-# - FutureWarning: join parameter default will change in future versions
-warnings.filterwarnings(
- 'ignore',
- category=FutureWarning,
- message="In a future version of xarray the default value for join will change from join='outer' to join='exact'",
- module='linopy',
-)
-
-# numpy: Core numerical library
-# - RuntimeWarning: Binary incompatibility warnings from compiled extensions (safe to ignore). numpy 1->2
-warnings.filterwarnings('ignore', category=RuntimeWarning, message='numpy\\.ndarray size changed')
diff --git a/flixopt/clustering.py b/flixopt/clustering.py
deleted file mode 100644
index d392167a1..000000000
--- a/flixopt/clustering.py
+++ /dev/null
@@ -1,431 +0,0 @@
-"""
-This module contains the Clustering functionality for the flixopt framework.
-Through this, clustering TimeSeriesData is possible.
-"""
-
-from __future__ import annotations
-
-import copy
-import logging
-import timeit
-from typing import TYPE_CHECKING
-
-import numpy as np
-
-try:
- import tsam.timeseriesaggregation as tsam
-
- TSAM_AVAILABLE = True
-except ImportError:
- TSAM_AVAILABLE = False
-
-from .color_processing import process_colors
-from .components import Storage
-from .config import CONFIG
-from .plot_result import PlotResult
-from .structure import (
- FlowSystemModel,
- Submodel,
-)
-
-if TYPE_CHECKING:
- import linopy
- import pandas as pd
-
- from .core import Scalar, TimeSeriesData
- from .elements import Component
- from .flow_system import FlowSystem
-
-logger = logging.getLogger('flixopt')
-
-
-class Clustering:
- """
- Clustering organizing class
- """
-
- def __init__(
- self,
- original_data: pd.DataFrame,
- hours_per_time_step: Scalar,
- hours_per_period: Scalar,
- nr_of_periods: int = 8,
- weights: dict[str, float] | None = None,
- time_series_for_high_peaks: list[str] | None = None,
- time_series_for_low_peaks: list[str] | None = None,
- ):
- """
- Args:
- original_data: The original data to aggregate
- hours_per_time_step: The duration of each timestep in hours.
- hours_per_period: The duration of each period in hours.
- nr_of_periods: The number of typical periods to use in the aggregation.
- weights: The weights for aggregation. If None, all time series are equally weighted.
- time_series_for_high_peaks: List of time series to use for explicitly selecting periods with high values.
- time_series_for_low_peaks: List of time series to use for explicitly selecting periods with low values.
- """
- if not TSAM_AVAILABLE:
- raise ImportError(
- "The 'tsam' package is required for clustering functionality. Install it with 'pip install tsam'."
- )
- self.original_data = copy.deepcopy(original_data)
- self.hours_per_time_step = hours_per_time_step
- self.hours_per_period = hours_per_period
- self.nr_of_periods = nr_of_periods
- self.nr_of_time_steps = len(self.original_data.index)
- self.weights = weights or {}
- self.time_series_for_high_peaks = time_series_for_high_peaks or []
- self.time_series_for_low_peaks = time_series_for_low_peaks or []
-
- self.aggregated_data: pd.DataFrame | None = None
- self.clustering_duration_seconds = None
- self.tsam: tsam.TimeSeriesAggregation | None = None
-
- def cluster(self) -> None:
- """
- DurchfΓΌhrung der Zeitreihenaggregation
- """
- start_time = timeit.default_timer()
- # Erstellen des aggregation objects
- self.tsam = tsam.TimeSeriesAggregation(
- self.original_data,
- noTypicalPeriods=self.nr_of_periods,
- hoursPerPeriod=self.hours_per_period,
- resolution=self.hours_per_time_step,
- clusterMethod='k_means',
- extremePeriodMethod='new_cluster_center'
- if self.use_extreme_periods
- else 'None', # Wenn Extremperioden eingebunden werden sollen, nutze die Methode 'new_cluster_center' aus tsam
- weightDict={name: weight for name, weight in self.weights.items() if name in self.original_data.columns},
- addPeakMax=self.time_series_for_high_peaks,
- addPeakMin=self.time_series_for_low_peaks,
- )
-
- self.tsam.createTypicalPeriods() # AusfΓΌhren der Aggregation/Clustering
- self.aggregated_data = self.tsam.predictOriginalData()
-
- self.clustering_duration_seconds = timeit.default_timer() - start_time # Zeit messen:
- if logger.isEnabledFor(logging.INFO):
- logger.info(self.describe_clusters())
-
- def describe_clusters(self) -> str:
- description = {}
- for cluster in self.get_cluster_indices().keys():
- description[cluster] = [
- str(indexVector[0]) + '...' + str(indexVector[-1])
- for indexVector in self.get_cluster_indices()[cluster]
- ]
-
- if self.use_extreme_periods:
- # Zeitreihe rauslΓΆschen:
- extreme_periods = self.tsam.extremePeriods.copy()
- for key in extreme_periods:
- del extreme_periods[key]['profile']
- else:
- extreme_periods = {}
-
- return (
- f'{"":#^80}\n'
- f'{" Clustering ":#^80}\n'
- f'periods_order:\n'
- f'{self.tsam.clusterOrder}\n'
- f'clusterPeriodNoOccur:\n'
- f'{self.tsam.clusterPeriodNoOccur}\n'
- f'index_vectors_of_clusters:\n'
- f'{description}\n'
- f'{"":#^80}\n'
- f'extreme_periods:\n'
- f'{extreme_periods}\n'
- f'{"":#^80}'
- )
-
- @property
- def use_extreme_periods(self):
- return self.time_series_for_high_peaks or self.time_series_for_low_peaks
-
- def plot(self, colormap: str | None = None, show: bool | None = None) -> PlotResult:
- """Plot original vs aggregated data comparison.
-
- Visualizes the original time series (dashed lines) overlaid with
- the aggregated/clustered time series (solid lines) for comparison.
-
- Args:
- colormap: Colorscale name for the time series colors.
- Defaults to CONFIG.Plotting.default_qualitative_colorscale.
- show: Whether to display the figure.
- Defaults to CONFIG.Plotting.default_show.
-
- Returns:
- PlotResult containing the comparison figure and underlying data.
-
- Examples:
- >>> clustering.cluster()
- >>> clustering.plot()
- >>> clustering.plot(colormap='Set2', show=False).to_html('clustering.html')
- """
- import plotly.express as px
- import xarray as xr
-
- df_org = self.original_data.copy().rename(
- columns={col: f'Original - {col}' for col in self.original_data.columns}
- )
- df_agg = self.aggregated_data.copy().rename(
- columns={col: f'Aggregated - {col}' for col in self.aggregated_data.columns}
- )
- colors = list(
- process_colors(colormap or CONFIG.Plotting.default_qualitative_colorscale, list(df_org.columns)).values()
- )
-
- # Create line plot for original data (dashed)
- index_name = df_org.index.name or 'index'
- df_org_long = df_org.reset_index().melt(id_vars=index_name, var_name='variable', value_name='value')
- fig = px.line(df_org_long, x=index_name, y='value', color='variable', color_discrete_sequence=colors)
- for trace in fig.data:
- trace.update(line=dict(dash='dash'))
-
- # Add aggregated data (solid lines)
- df_agg_long = df_agg.reset_index().melt(id_vars=index_name, var_name='variable', value_name='value')
- fig2 = px.line(df_agg_long, x=index_name, y='value', color='variable', color_discrete_sequence=colors)
- for trace in fig2.data:
- fig.add_trace(trace)
-
- fig.update_layout(
- title='Original vs Aggregated Data (original = ---)',
- xaxis_title='Time in h',
- yaxis_title='Value',
- )
-
- # Build xarray Dataset with both original and aggregated data
- data = xr.Dataset(
- {
- 'original': self.original_data.to_xarray().to_array(dim='variable'),
- 'aggregated': self.aggregated_data.to_xarray().to_array(dim='variable'),
- }
- )
- result = PlotResult(data=data, figure=fig)
-
- if show is None:
- show = CONFIG.Plotting.default_show
- if show:
- result.show()
-
- return result
-
- def get_cluster_indices(self) -> dict[str, list[np.ndarray]]:
- """
- Generates a dictionary that maps each cluster to a list of index vectors representing the time steps
- assigned to that cluster for each period.
-
- Returns:
- dict: {cluster_0: [index_vector_3, index_vector_7, ...],
- cluster_1: [index_vector_1],
- ...}
- """
- clusters = self.tsam.clusterPeriodNoOccur.keys()
- index_vectors = {cluster: [] for cluster in clusters}
-
- period_length = len(self.tsam.stepIdx)
- total_steps = len(self.tsam.timeSeries)
-
- for period, cluster_id in enumerate(self.tsam.clusterOrder):
- start_idx = period * period_length
- end_idx = np.min([start_idx + period_length, total_steps])
- index_vectors[cluster_id].append(np.arange(start_idx, end_idx))
-
- return index_vectors
-
- def get_equation_indices(self, skip_first_index_of_period: bool = True) -> tuple[np.ndarray, np.ndarray]:
- """
- Generates pairs of indices for the equations by comparing index vectors of the same cluster.
- If `skip_first_index_of_period` is True, the first index of each period is skipped.
-
- Args:
- skip_first_index_of_period (bool): Whether to include or skip the first index of each period.
-
- Returns:
- tuple[np.ndarray, np.ndarray]: Two arrays of indices.
- """
- idx_var1 = []
- idx_var2 = []
-
- # Iterate through cluster index vectors
- for index_vectors in self.get_cluster_indices().values():
- if len(index_vectors) <= 1: # Only proceed if cluster has more than one period
- continue
-
- # Process the first vector, optionally skip first index
- first_vector = index_vectors[0][1:] if skip_first_index_of_period else index_vectors[0]
-
- # Compare first vector to others in the cluster
- for other_vector in index_vectors[1:]:
- if skip_first_index_of_period:
- other_vector = other_vector[1:]
-
- # Compare elements up to the minimum length of both vectors
- min_len = min(len(first_vector), len(other_vector))
- idx_var1.extend(first_vector[:min_len])
- idx_var2.extend(other_vector[:min_len])
-
- # Convert lists to numpy arrays
- return np.array(idx_var1), np.array(idx_var2)
-
-
-class ClusteringParameters:
- def __init__(
- self,
- hours_per_period: float,
- nr_of_periods: int,
- fix_storage_flows: bool,
- aggregate_data_and_fix_non_binary_vars: bool,
- percentage_of_period_freedom: float = 0,
- penalty_of_period_freedom: float = 0,
- time_series_for_high_peaks: list[TimeSeriesData] | None = None,
- time_series_for_low_peaks: list[TimeSeriesData] | None = None,
- ):
- """
- Initializes clustering parameters for time series data
-
- Args:
- hours_per_period: Duration of each period in hours.
- nr_of_periods: Number of typical periods to use in the aggregation.
- fix_storage_flows: Whether to aggregate storage flows (load/unload); if other flows
- are fixed, fixing storage flows is usually not required.
- aggregate_data_and_fix_non_binary_vars: Whether to aggregate all time series data, which allows to fix all time series variables (like flow_rate),
- or only fix binary variables. If False non time_series data is changed!! If True, the mathematical Problem
- is simplified even further.
- percentage_of_period_freedom: Specifies the maximum percentage (0β100) of binary values within each period
- that can deviate as "free variables", chosen by the solver (default is 0).
- This allows binary variables to be 'partly equated' between aggregated periods.
- penalty_of_period_freedom: The penalty associated with each "free variable"; defaults to 0. Added to Penalty
- time_series_for_high_peaks: List of TimeSeriesData to use for explicitly selecting periods with high values.
- time_series_for_low_peaks: List of TimeSeriesData to use for explicitly selecting periods with low values.
- """
- self.hours_per_period = hours_per_period
- self.nr_of_periods = nr_of_periods
- self.fix_storage_flows = fix_storage_flows
- self.aggregate_data_and_fix_non_binary_vars = aggregate_data_and_fix_non_binary_vars
- self.percentage_of_period_freedom = percentage_of_period_freedom
- self.penalty_of_period_freedom = penalty_of_period_freedom
- self.time_series_for_high_peaks: list[TimeSeriesData] = time_series_for_high_peaks or []
- self.time_series_for_low_peaks: list[TimeSeriesData] = time_series_for_low_peaks or []
-
- @property
- def use_extreme_periods(self):
- return self.time_series_for_high_peaks or self.time_series_for_low_peaks
-
- @property
- def labels_for_high_peaks(self) -> list[str]:
- return [ts.name for ts in self.time_series_for_high_peaks]
-
- @property
- def labels_for_low_peaks(self) -> list[str]:
- return [ts.name for ts in self.time_series_for_low_peaks]
-
- @property
- def use_low_peaks(self) -> bool:
- return bool(self.time_series_for_low_peaks)
-
-
-class ClusteringModel(Submodel):
- """The ClusteringModel holds equations and variables related to the Clustering of a FlowSystem.
- It creates Equations that equates indices of variables, and introduces penalties related to binary variables, that
- escape the equation to their related binaries in other periods"""
-
- def __init__(
- self,
- model: FlowSystemModel,
- clustering_parameters: ClusteringParameters,
- flow_system: FlowSystem,
- clustering_data: Clustering,
- components_to_clusterize: list[Component] | None,
- ):
- """
- Modeling-Element for "index-equating"-equations
- """
- super().__init__(model, label_of_element='Clustering', label_of_model='Clustering')
- self.flow_system = flow_system
- self.clustering_parameters = clustering_parameters
- self.clustering_data = clustering_data
- self.components_to_clusterize = components_to_clusterize
-
- def do_modeling(self):
- if not self.components_to_clusterize:
- components = self.flow_system.components.values()
- else:
- components = [component for component in self.components_to_clusterize]
-
- indices = self.clustering_data.get_equation_indices(skip_first_index_of_period=True)
-
- time_variables: set[str] = {
- name for name in self._model.variables if 'time' in self._model.variables[name].dims
- }
- binary_variables: set[str] = set(self._model.variables.binaries)
- binary_time_variables: set[str] = time_variables & binary_variables
-
- for component in components:
- if isinstance(component, Storage) and not self.clustering_parameters.fix_storage_flows:
- continue # Fix Nothing in The Storage
-
- all_variables_of_component = set(component.submodel.variables)
-
- if self.clustering_parameters.aggregate_data_and_fix_non_binary_vars:
- relevant_variables = component.submodel.variables[all_variables_of_component & time_variables]
- else:
- relevant_variables = component.submodel.variables[all_variables_of_component & binary_time_variables]
- for variable in relevant_variables:
- self._equate_indices(component.submodel.variables[variable], indices)
-
- penalty = self.clustering_parameters.penalty_of_period_freedom
- if (self.clustering_parameters.percentage_of_period_freedom > 0) and penalty != 0:
- from .effects import PENALTY_EFFECT_LABEL
-
- for variable_name in self.variables_direct:
- variable = self.variables_direct[variable_name]
- # Sum correction variables over all dimensions to get periodic penalty contribution
- self._model.effects.add_share_to_effects(
- name='Aggregation',
- expressions={PENALTY_EFFECT_LABEL: (variable * penalty).sum('time')},
- target='periodic',
- )
-
- def _equate_indices(self, variable: linopy.Variable, indices: tuple[np.ndarray, np.ndarray]) -> None:
- assert len(indices[0]) == len(indices[1]), 'The length of the indices must match!!'
- length = len(indices[0])
-
- # Gleichung:
- # eq1: x(p1,t) - x(p3,t) = 0 # wobei p1 und p3 im gleichen Cluster sind und t = 0..N_p
- con = self.add_constraints(
- variable.isel(time=indices[0]) - variable.isel(time=indices[1]) == 0,
- short_name=f'equate_indices|{variable.name}',
- )
-
- # Korrektur: (bisher nur fΓΌr BinΓ€rvariablen:)
- if (
- variable.name in self._model.variables.binaries
- and self.clustering_parameters.percentage_of_period_freedom > 0
- ):
- sel = variable.isel(time=indices[0])
- coords = {d: sel.indexes[d] for d in sel.dims}
- var_k1 = self.add_variables(binary=True, coords=coords, short_name=f'correction1|{variable.name}')
-
- var_k0 = self.add_variables(binary=True, coords=coords, short_name=f'correction0|{variable.name}')
-
- # equation extends ...
- # --> On(p3) can be 0/1 independent of On(p1,t)!
- # eq1: On(p1,t) - On(p3,t) + K1(p3,t) - K0(p3,t) = 0
- # --> correction On(p3) can be:
- # On(p1,t) = 1 -> On(p3) can be 0 -> K0=1 (,K1=0)
- # On(p1,t) = 0 -> On(p3) can be 1 -> K1=1 (,K0=1)
- con.lhs += 1 * var_k1 - 1 * var_k0
-
- # interlock var_k1 and var_K2:
- # eq: var_k0(t)+var_k1(t) <= 1
- self.add_constraints(var_k0 + var_k1 <= 1, short_name=f'lock_k0_and_k1|{variable.name}')
-
- # Begrenzung der Korrektur-Anzahl:
- # eq: sum(K) <= n_Corr_max
- limit = int(np.floor(self.clustering_parameters.percentage_of_period_freedom / 100 * length))
- self.add_constraints(
- var_k0.sum(dim='time') + var_k1.sum(dim='time') <= limit,
- short_name=f'limit_corrections|{variable.name}',
- )
diff --git a/flixopt/clustering/__init__.py b/flixopt/clustering/__init__.py
new file mode 100644
index 000000000..a5446a524
--- /dev/null
+++ b/flixopt/clustering/__init__.py
@@ -0,0 +1,42 @@
+"""
+Time Series Aggregation Module for flixopt.
+
+This module provides data structures for time series clustering/aggregation.
+
+Key classes:
+- ClusterResult: Universal result container for clustering
+- ClusterStructure: Hierarchical structure info for storage inter-cluster linking
+- Clustering: Stored on FlowSystem after clustering
+
+Example usage:
+
+ # Cluster a FlowSystem to reduce timesteps
+ fs_clustered = flow_system.transform.cluster(
+ n_clusters=8,
+ cluster_duration='1D',
+ time_series_for_high_peaks=['Demand|fixed_relative_profile'],
+ )
+
+ # Access clustering metadata
+ info = fs_clustered.clustering
+ print(f'Number of clusters: {info.result.cluster_structure.n_clusters}')
+
+ # Expand solution back to full resolution
+ fs_expanded = fs_clustered.transform.expand_solution()
+"""
+
+from .base import (
+ Clustering,
+ ClusterResult,
+ ClusterStructure,
+ create_cluster_structure_from_mapping,
+)
+
+__all__ = [
+ # Core classes
+ 'ClusterResult',
+ 'Clustering',
+ 'ClusterStructure',
+ # Utilities
+ 'create_cluster_structure_from_mapping',
+]
diff --git a/flixopt/clustering/base.py b/flixopt/clustering/base.py
new file mode 100644
index 000000000..0f154484b
--- /dev/null
+++ b/flixopt/clustering/base.py
@@ -0,0 +1,1179 @@
+"""
+Base classes and data structures for time series aggregation (clustering).
+
+This module provides an abstraction layer for time series aggregation that
+supports multiple backends (TSAM, manual/external, etc.).
+
+Terminology:
+- "cluster" = a group of similar time chunks (e.g., similar days grouped together)
+- "typical period" = a representative time chunk for a cluster (TSAM terminology)
+- "cluster duration" = the length of each time chunk (e.g., 24h for daily clustering)
+
+Note: This is separate from the model's "period" dimension (years/months) and
+"scenario" dimension. The aggregation operates on the 'time' dimension.
+
+All data structures use xarray for consistent handling of coordinates.
+"""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import TYPE_CHECKING, Any
+
+import numpy as np
+import pandas as pd
+import xarray as xr
+
+if TYPE_CHECKING:
+ from ..color_processing import ColorType
+ from ..plot_result import PlotResult
+ from ..statistics_accessor import SelectType
+
+
+@dataclass
+class ClusterStructure:
+ """Structure information for inter-cluster storage linking.
+
+ This class captures the hierarchical structure of time series clustering,
+ which is needed for proper storage state-of-charge tracking across
+ typical periods when using cluster().
+
+ Note: The "original_cluster" dimension indexes the original cluster-sized
+ time segments (e.g., 0..364 for 365 days), NOT the model's "period" dimension
+ (years). Each original segment gets assigned to a representative cluster.
+
+ Attributes:
+ cluster_order: Maps original cluster index β representative cluster ID.
+ dims: [original_cluster] for simple case, or
+ [original_cluster, period, scenario] for multi-period/scenario systems.
+ Values are cluster IDs (0 to n_clusters-1).
+ cluster_occurrences: Count of how many original time chunks each cluster represents.
+ dims: [cluster] for simple case, or [cluster, period, scenario] for multi-dim.
+ n_clusters: Number of distinct clusters (typical periods).
+ timesteps_per_cluster: Number of timesteps in each cluster (e.g., 24 for daily).
+
+ Example:
+ For 365 days clustered into 8 typical days:
+ - cluster_order: shape (365,), values 0-7 indicating which cluster each day belongs to
+ - cluster_occurrences: shape (8,), e.g., [45, 46, 46, 46, 46, 45, 45, 46]
+ - n_clusters: 8
+ - timesteps_per_cluster: 24 (for hourly data)
+
+ For multi-scenario (e.g., 2 scenarios):
+ - cluster_order: shape (365, 2) with dims [original_cluster, scenario]
+ - cluster_occurrences: shape (8, 2) with dims [cluster, scenario]
+ """
+
+ cluster_order: xr.DataArray
+ cluster_occurrences: xr.DataArray
+ n_clusters: int | xr.DataArray
+ timesteps_per_cluster: int
+
+ def __post_init__(self):
+ """Validate and ensure proper DataArray formatting."""
+ # Ensure cluster_order is a DataArray with proper dims
+ if not isinstance(self.cluster_order, xr.DataArray):
+ self.cluster_order = xr.DataArray(self.cluster_order, dims=['original_cluster'], name='cluster_order')
+ elif self.cluster_order.name is None:
+ self.cluster_order = self.cluster_order.rename('cluster_order')
+
+ # Ensure cluster_occurrences is a DataArray with proper dims
+ if not isinstance(self.cluster_occurrences, xr.DataArray):
+ self.cluster_occurrences = xr.DataArray(
+ self.cluster_occurrences, dims=['cluster'], name='cluster_occurrences'
+ )
+ elif self.cluster_occurrences.name is None:
+ self.cluster_occurrences = self.cluster_occurrences.rename('cluster_occurrences')
+
+ def __repr__(self) -> str:
+ n_clusters = (
+ int(self.n_clusters) if isinstance(self.n_clusters, (int, np.integer)) else int(self.n_clusters.values)
+ )
+ occ = [int(self.cluster_occurrences.sel(cluster=c).values) for c in range(n_clusters)]
+ return (
+ f'ClusterStructure(\n'
+ f' {self.n_original_clusters} original periods β {n_clusters} clusters\n'
+ f' timesteps_per_cluster={self.timesteps_per_cluster}\n'
+ f' occurrences={occ}\n'
+ f')'
+ )
+
+ def _create_reference_structure(self) -> tuple[dict, dict[str, xr.DataArray]]:
+ """Create reference structure for serialization."""
+ ref = {'__class__': self.__class__.__name__}
+ arrays = {}
+
+ # Store DataArrays with references
+ arrays[str(self.cluster_order.name)] = self.cluster_order
+ ref['cluster_order'] = f':::{self.cluster_order.name}'
+
+ arrays[str(self.cluster_occurrences.name)] = self.cluster_occurrences
+ ref['cluster_occurrences'] = f':::{self.cluster_occurrences.name}'
+
+ # Store scalar values
+ if isinstance(self.n_clusters, xr.DataArray):
+ n_clusters_name = self.n_clusters.name or 'n_clusters'
+ self.n_clusters = self.n_clusters.rename(n_clusters_name)
+ arrays[n_clusters_name] = self.n_clusters
+ ref['n_clusters'] = f':::{n_clusters_name}'
+ else:
+ ref['n_clusters'] = int(self.n_clusters)
+
+ ref['timesteps_per_cluster'] = self.timesteps_per_cluster
+
+ return ref, arrays
+
+ @property
+ def n_original_clusters(self) -> int:
+ """Number of original periods (before clustering)."""
+ return len(self.cluster_order.coords['original_cluster'])
+
+ @property
+ def has_multi_dims(self) -> bool:
+ """Check if cluster_order has period/scenario dimensions."""
+ return 'period' in self.cluster_order.dims or 'scenario' in self.cluster_order.dims
+
+ def get_cluster_order_for_slice(self, period: str | None = None, scenario: str | None = None) -> np.ndarray:
+ """Get cluster_order for a specific (period, scenario) combination.
+
+ Args:
+ period: Period label (None if no period dimension).
+ scenario: Scenario label (None if no scenario dimension).
+
+ Returns:
+ 1D numpy array of cluster indices for the specified slice.
+ """
+ order = self.cluster_order
+ if 'period' in order.dims and period is not None:
+ order = order.sel(period=period)
+ if 'scenario' in order.dims and scenario is not None:
+ order = order.sel(scenario=scenario)
+ return order.values.astype(int)
+
+ def get_cluster_occurrences_for_slice(
+ self, period: str | None = None, scenario: str | None = None
+ ) -> dict[int, int]:
+ """Get cluster occurrence counts for a specific (period, scenario) combination.
+
+ Args:
+ period: Period label (None if no period dimension).
+ scenario: Scenario label (None if no scenario dimension).
+
+ Returns:
+ Dict mapping cluster ID to occurrence count.
+ """
+ occurrences = self.cluster_occurrences
+ if 'period' in occurrences.dims and period is not None:
+ occurrences = occurrences.sel(period=period)
+ if 'scenario' in occurrences.dims and scenario is not None:
+ occurrences = occurrences.sel(scenario=scenario)
+ return {int(c): int(occurrences.sel(cluster=c).values) for c in occurrences.coords['cluster'].values}
+
+ def get_cluster_weight_per_timestep(self) -> xr.DataArray:
+ """Get weight for each representative timestep.
+
+ Returns an array where each timestep's weight equals the number of
+ original periods its cluster represents.
+
+ Returns:
+ DataArray with dims [time] or [time, period, scenario].
+ """
+ # Expand cluster_occurrences to timesteps
+ n_clusters = (
+ int(self.n_clusters) if isinstance(self.n_clusters, (int, np.integer)) else int(self.n_clusters.values)
+ )
+
+ # Get occurrence for each cluster, then repeat for timesteps
+ weights_list = []
+ for c in range(n_clusters):
+ occ = self.cluster_occurrences.sel(cluster=c)
+ weights_list.append(np.repeat(float(occ.values), self.timesteps_per_cluster))
+
+ weights = np.concatenate(weights_list)
+ return xr.DataArray(
+ weights,
+ dims=['time'],
+ coords={'time': np.arange(len(weights))},
+ name='cluster_weight',
+ )
+
+ def plot(self, colors: str | list[str] | None = None, show: bool | None = None) -> PlotResult:
+ """Plot cluster assignment visualization.
+
+ Shows which cluster each original period belongs to, and the
+ number of occurrences per cluster.
+
+ Args:
+ colors: Colorscale name (str) or list of colors.
+ Defaults to CONFIG.Plotting.default_sequential_colorscale.
+ show: Whether to display the figure. Defaults to CONFIG.Plotting.default_show.
+
+ Returns:
+ PlotResult containing the figure and underlying data.
+ """
+ from ..config import CONFIG
+ from ..plot_result import PlotResult
+
+ n_clusters = (
+ int(self.n_clusters) if isinstance(self.n_clusters, (int, np.integer)) else int(self.n_clusters.values)
+ )
+
+ cluster_order = self.get_cluster_order_for_slice()
+
+ # Build DataArray for fxplot heatmap
+ cluster_da = xr.DataArray(
+ cluster_order.reshape(1, -1),
+ dims=['y', 'original_cluster'],
+ coords={'y': ['Cluster'], 'original_cluster': range(1, len(cluster_order) + 1)},
+ name='cluster_assignment',
+ )
+
+ # Use fxplot.heatmap for smart defaults
+ colorscale = colors or CONFIG.Plotting.default_sequential_colorscale
+ fig = cluster_da.fxplot.heatmap(
+ colors=colorscale,
+ title=f'Cluster Assignment ({self.n_original_clusters} periods β {n_clusters} clusters)',
+ )
+ fig.update_yaxes(showticklabels=False)
+ fig.update_coloraxes(colorbar_title='Cluster')
+
+ # Build data for PlotResult
+ data = xr.Dataset(
+ {
+ 'cluster_order': self.cluster_order,
+ 'cluster_occurrences': self.cluster_occurrences,
+ }
+ )
+ plot_result = PlotResult(data=data, figure=fig)
+
+ if show is None:
+ show = CONFIG.Plotting.default_show
+ if show:
+ plot_result.show()
+
+ return plot_result
+
+
+@dataclass
+class ClusterResult:
+ """Universal result from any time series aggregation method.
+
+ This dataclass captures all information needed to:
+ 1. Transform a FlowSystem to use aggregated (clustered) timesteps
+ 2. Expand a solution back to original resolution
+ 3. Properly weight results for statistics
+
+ Attributes:
+ timestep_mapping: Maps each original timestep to its representative index.
+ dims: [original_time] for simple case, or
+ [original_time, period, scenario] for multi-period/scenario systems.
+ Values are indices into the representative timesteps (0 to n_representatives-1).
+ n_representatives: Number of representative timesteps after aggregation.
+ representative_weights: Weight for each representative timestep.
+ dims: [time] or [time, period, scenario]
+ Typically equals the number of original timesteps each representative covers.
+ Used as cluster_weight in the FlowSystem.
+ aggregated_data: Time series data aggregated to representative timesteps.
+ Optional - some backends may not aggregate data.
+ cluster_structure: Hierarchical clustering structure for storage linking.
+ Optional - only needed when using cluster() mode.
+ original_data: Reference to original data before aggregation.
+ Optional - useful for expand_solution().
+
+ Example:
+ For 8760 hourly timesteps clustered into 192 representative timesteps (8 clusters x 24h):
+ - timestep_mapping: shape (8760,), values 0-191
+ - n_representatives: 192
+ - representative_weights: shape (192,), summing to 8760
+ """
+
+ timestep_mapping: xr.DataArray
+ n_representatives: int | xr.DataArray
+ representative_weights: xr.DataArray
+ aggregated_data: xr.Dataset | None = None
+ cluster_structure: ClusterStructure | None = None
+ original_data: xr.Dataset | None = None
+
+ def __post_init__(self):
+ """Validate and ensure proper DataArray formatting."""
+ # Ensure timestep_mapping is a DataArray
+ if not isinstance(self.timestep_mapping, xr.DataArray):
+ self.timestep_mapping = xr.DataArray(self.timestep_mapping, dims=['original_time'], name='timestep_mapping')
+ elif self.timestep_mapping.name is None:
+ self.timestep_mapping = self.timestep_mapping.rename('timestep_mapping')
+
+ # Ensure representative_weights is a DataArray
+ # Can be (cluster, time) for 2D structure or (time,) for flat structure
+ if not isinstance(self.representative_weights, xr.DataArray):
+ self.representative_weights = xr.DataArray(self.representative_weights, name='representative_weights')
+ elif self.representative_weights.name is None:
+ self.representative_weights = self.representative_weights.rename('representative_weights')
+
+ def __repr__(self) -> str:
+ n_rep = (
+ int(self.n_representatives)
+ if isinstance(self.n_representatives, (int, np.integer))
+ else int(self.n_representatives.values)
+ )
+ has_structure = self.cluster_structure is not None
+ has_data = self.original_data is not None and self.aggregated_data is not None
+ return (
+ f'ClusterResult(\n'
+ f' {self.n_original_timesteps} original β {n_rep} representative timesteps\n'
+ f' weights sum={float(self.representative_weights.sum().values):.0f}\n'
+ f' cluster_structure={has_structure}, data={has_data}\n'
+ f')'
+ )
+
+ def _create_reference_structure(self) -> tuple[dict, dict[str, xr.DataArray]]:
+ """Create reference structure for serialization."""
+ ref = {'__class__': self.__class__.__name__}
+ arrays = {}
+
+ # Store DataArrays with references
+ arrays[str(self.timestep_mapping.name)] = self.timestep_mapping
+ ref['timestep_mapping'] = f':::{self.timestep_mapping.name}'
+
+ arrays[str(self.representative_weights.name)] = self.representative_weights
+ ref['representative_weights'] = f':::{self.representative_weights.name}'
+
+ # Store scalar values
+ if isinstance(self.n_representatives, xr.DataArray):
+ n_rep_name = self.n_representatives.name or 'n_representatives'
+ self.n_representatives = self.n_representatives.rename(n_rep_name)
+ arrays[n_rep_name] = self.n_representatives
+ ref['n_representatives'] = f':::{n_rep_name}'
+ else:
+ ref['n_representatives'] = int(self.n_representatives)
+
+ # Store nested ClusterStructure if present
+ if self.cluster_structure is not None:
+ cs_ref, cs_arrays = self.cluster_structure._create_reference_structure()
+ ref['cluster_structure'] = cs_ref
+ arrays.update(cs_arrays)
+
+ # Skip aggregated_data and original_data - not needed for serialization
+
+ return ref, arrays
+
+ @property
+ def n_original_timesteps(self) -> int:
+ """Number of original timesteps (before aggregation)."""
+ return len(self.timestep_mapping.coords['original_time'])
+
+ def get_expansion_mapping(self) -> xr.DataArray:
+ """Get mapping from original timesteps to representative indices.
+
+ This is the same as timestep_mapping but ensures proper naming
+ for use in expand_solution().
+
+ Returns:
+ DataArray mapping original timesteps to representative indices.
+ """
+ return self.timestep_mapping.rename('expansion_mapping')
+
+ def get_timestep_mapping_for_slice(self, period: str | None = None, scenario: str | None = None) -> np.ndarray:
+ """Get timestep_mapping for a specific (period, scenario) combination.
+
+ Args:
+ period: Period label (None if no period dimension).
+ scenario: Scenario label (None if no scenario dimension).
+
+ Returns:
+ 1D numpy array of representative timestep indices for the specified slice.
+ """
+ mapping = self.timestep_mapping
+ if 'period' in mapping.dims and period is not None:
+ mapping = mapping.sel(period=period)
+ if 'scenario' in mapping.dims and scenario is not None:
+ mapping = mapping.sel(scenario=scenario)
+ return mapping.values.astype(int)
+
+ def expand_data(self, aggregated: xr.DataArray, original_time: xr.DataArray | None = None) -> xr.DataArray:
+ """Expand aggregated data back to original timesteps.
+
+ Uses the stored timestep_mapping to map each original timestep to its
+ representative value from the aggregated data. Handles multi-dimensional
+ data with period/scenario dimensions.
+
+ Args:
+ aggregated: DataArray with aggregated (reduced) time dimension.
+ original_time: Original time coordinates. If None, uses coords from
+ original_data if available.
+
+ Returns:
+ DataArray expanded to original timesteps.
+
+ Example:
+ >>> result = fs_clustered.clustering.result
+ >>> aggregated_values = result.aggregated_data['Demand|profile']
+ >>> expanded = result.expand_data(aggregated_values)
+ >>> len(expanded.time) == len(original_timesteps) # True
+ """
+ import pandas as pd
+
+ if original_time is None:
+ if self.original_data is None:
+ raise ValueError('original_time required when original_data is not available')
+ original_time = self.original_data.coords['time']
+
+ timestep_mapping = self.timestep_mapping
+ has_periods = 'period' in timestep_mapping.dims
+ has_scenarios = 'scenario' in timestep_mapping.dims
+ has_cluster_dim = 'cluster' in aggregated.dims
+
+ # Simple case: no period/scenario dimensions
+ if not has_periods and not has_scenarios:
+ mapping = timestep_mapping.values
+ if has_cluster_dim:
+ # 2D cluster structure: convert flat indices to (cluster, time_within)
+ # Use cluster_structure's timesteps_per_cluster, not aggregated.sizes['time']
+ # because the solution may include extra timesteps (timesteps_extra)
+ timesteps_per_cluster = self.cluster_structure.timesteps_per_cluster
+ cluster_ids = mapping // timesteps_per_cluster
+ time_within = mapping % timesteps_per_cluster
+ expanded_values = aggregated.values[cluster_ids, time_within]
+ else:
+ expanded_values = aggregated.values[mapping]
+ return xr.DataArray(
+ expanded_values,
+ coords={'time': original_time},
+ dims=['time'],
+ attrs=aggregated.attrs,
+ )
+
+ # Multi-dimensional: expand each (period, scenario) slice and recombine
+ periods = list(timestep_mapping.coords['period'].values) if has_periods else [None]
+ scenarios = list(timestep_mapping.coords['scenario'].values) if has_scenarios else [None]
+
+ expanded_slices: dict[tuple, xr.DataArray] = {}
+ for p in periods:
+ for s in scenarios:
+ # Get mapping for this slice
+ mapping_slice = timestep_mapping
+ if p is not None:
+ mapping_slice = mapping_slice.sel(period=p)
+ if s is not None:
+ mapping_slice = mapping_slice.sel(scenario=s)
+ mapping = mapping_slice.values
+
+ # Select the data slice
+ selector = {}
+ if p is not None and 'period' in aggregated.dims:
+ selector['period'] = p
+ if s is not None and 'scenario' in aggregated.dims:
+ selector['scenario'] = s
+
+ slice_da = aggregated.sel(**selector, drop=True) if selector else aggregated
+
+ if has_cluster_dim:
+ # 2D cluster structure: convert flat indices to (cluster, time_within)
+ # Use cluster_structure's timesteps_per_cluster, not slice_da.sizes['time']
+ # because the solution may include extra timesteps (timesteps_extra)
+ timesteps_per_cluster = self.cluster_structure.timesteps_per_cluster
+ cluster_ids = mapping // timesteps_per_cluster
+ time_within = mapping % timesteps_per_cluster
+ expanded_values = slice_da.values[cluster_ids, time_within]
+ expanded = xr.DataArray(expanded_values, dims=['time'])
+ else:
+ expanded = slice_da.isel(time=xr.DataArray(mapping, dims=['time']))
+ expanded_slices[(p, s)] = expanded.assign_coords(time=original_time)
+
+ # Recombine slices using xr.concat
+ if has_periods and has_scenarios:
+ period_arrays = []
+ for p in periods:
+ scenario_arrays = [expanded_slices[(p, s)] for s in scenarios]
+ period_arrays.append(xr.concat(scenario_arrays, dim=pd.Index(scenarios, name='scenario')))
+ result = xr.concat(period_arrays, dim=pd.Index(periods, name='period'))
+ elif has_periods:
+ result = xr.concat([expanded_slices[(p, None)] for p in periods], dim=pd.Index(periods, name='period'))
+ else:
+ result = xr.concat(
+ [expanded_slices[(None, s)] for s in scenarios], dim=pd.Index(scenarios, name='scenario')
+ )
+
+ return result.transpose('time', ...).assign_attrs(aggregated.attrs)
+
+ def validate(self) -> None:
+ """Validate that all fields are consistent.
+
+ Raises:
+ ValueError: If validation fails.
+ """
+ n_rep = (
+ int(self.n_representatives)
+ if isinstance(self.n_representatives, (int, np.integer))
+ else int(self.n_representatives.max().values)
+ )
+
+ # Check mapping values are within range
+ max_idx = int(self.timestep_mapping.max().values)
+ if max_idx >= n_rep:
+ raise ValueError(f'timestep_mapping contains index {max_idx} but n_representatives is {n_rep}')
+
+ # Check weights dimensions
+ # representative_weights should have (cluster,) dimension with n_clusters elements
+ # (plus optional period/scenario dimensions)
+ if self.cluster_structure is not None:
+ n_clusters = self.cluster_structure.n_clusters
+ if 'cluster' in self.representative_weights.dims:
+ weights_n_clusters = self.representative_weights.sizes['cluster']
+ if weights_n_clusters != n_clusters:
+ raise ValueError(
+ f'representative_weights has {weights_n_clusters} clusters '
+ f'but cluster_structure has {n_clusters}'
+ )
+
+ # Check weights sum roughly equals number of original periods
+ # (each weight is how many original periods that cluster represents)
+ # Sum should be checked per period/scenario slice, not across all dimensions
+ if self.cluster_structure is not None:
+ n_original_clusters = self.cluster_structure.n_original_clusters
+ # Sum over cluster dimension only (keep period/scenario if present)
+ weight_sum_per_slice = self.representative_weights.sum(dim='cluster')
+ # Check each slice
+ if weight_sum_per_slice.size == 1:
+ # Simple case: no period/scenario
+ weight_sum = float(weight_sum_per_slice.values)
+ if abs(weight_sum - n_original_clusters) > 1e-6:
+ import warnings
+
+ warnings.warn(
+ f'representative_weights sum ({weight_sum}) does not match '
+ f'n_original_clusters ({n_original_clusters})',
+ stacklevel=2,
+ )
+ else:
+ # Multi-dimensional: check each slice
+ for val in weight_sum_per_slice.values.flat:
+ if abs(float(val) - n_original_clusters) > 1e-6:
+ import warnings
+
+ warnings.warn(
+ f'representative_weights sum per slice ({float(val)}) does not match '
+ f'n_original_clusters ({n_original_clusters})',
+ stacklevel=2,
+ )
+ break # Only warn once
+
+
+class ClusteringPlotAccessor:
+ """Plot accessor for Clustering objects.
+
+ Provides visualization methods for comparing original vs aggregated data
+ and understanding the clustering structure.
+
+ Example:
+ >>> fs_clustered = flow_system.transform.cluster(n_clusters=8, cluster_duration='1D')
+ >>> fs_clustered.clustering.plot.compare() # timeseries comparison
+ >>> fs_clustered.clustering.plot.compare(kind='duration_curve') # duration curve
+ >>> fs_clustered.clustering.plot.heatmap() # structure visualization
+ >>> fs_clustered.clustering.plot.clusters() # cluster profiles
+ """
+
+ def __init__(self, clustering: Clustering):
+ self._clustering = clustering
+
+ def compare(
+ self,
+ kind: str = 'timeseries',
+ variables: str | list[str] | None = None,
+ *,
+ select: SelectType | None = None,
+ colors: ColorType | None = None,
+ color: str | None = 'auto',
+ line_dash: str | None = 'representation',
+ facet_col: str | None = 'auto',
+ facet_row: str | None = 'auto',
+ show: bool | None = None,
+ **plotly_kwargs: Any,
+ ) -> PlotResult:
+ """Compare original vs aggregated data.
+
+ Args:
+ kind: Type of comparison plot.
+ - 'timeseries': Time series comparison (default)
+ - 'duration_curve': Sorted duration curve comparison
+ variables: Variable(s) to plot. Can be a string, list of strings,
+ or None to plot all time-varying variables.
+ select: xarray-style selection dict, e.g. {'scenario': 'Base Case'}.
+ colors: Color specification (colorscale name, color list, or label-to-color dict).
+ color: Dimension for line colors. 'auto' uses CONFIG priority (typically 'variable').
+ Use 'representation' to color by Original/Clustered instead of line_dash.
+ line_dash: Dimension for line dash styles. Defaults to 'representation'.
+ Set to None to disable line dash differentiation.
+ facet_col: Dimension for subplot columns. 'auto' uses CONFIG priority.
+ Use 'variable' to create separate columns per variable.
+ facet_row: Dimension for subplot rows. 'auto' uses CONFIG priority.
+ Use 'variable' to create separate rows per variable.
+ show: Whether to display the figure.
+ Defaults to CONFIG.Plotting.default_show.
+ **plotly_kwargs: Additional arguments passed to plotly.
+
+ Returns:
+ PlotResult containing the comparison figure and underlying data.
+ """
+ import pandas as pd
+
+ from ..config import CONFIG
+ from ..plot_result import PlotResult
+ from ..statistics_accessor import _apply_selection
+
+ if kind not in ('timeseries', 'duration_curve'):
+ raise ValueError(f"Unknown kind '{kind}'. Use 'timeseries' or 'duration_curve'.")
+
+ result = self._clustering.result
+ if result.original_data is None or result.aggregated_data is None:
+ raise ValueError('No original/aggregated data available for comparison')
+
+ resolved_variables = self._resolve_variables(variables)
+
+ # Build Dataset with variables as data_vars
+ data_vars = {}
+ for var in resolved_variables:
+ original = result.original_data[var]
+ clustered = result.expand_data(result.aggregated_data[var])
+ combined = xr.concat([original, clustered], dim=pd.Index(['Original', 'Clustered'], name='representation'))
+ data_vars[var] = combined
+ ds = xr.Dataset(data_vars)
+
+ # Apply selection
+ ds = _apply_selection(ds, select)
+
+ # For duration curve: flatten and sort values
+ if kind == 'duration_curve':
+ sorted_vars = {}
+ for var in ds.data_vars:
+ for rep in ds.coords['representation'].values:
+ values = np.sort(ds[var].sel(representation=rep).values.flatten())[::-1]
+ sorted_vars[(var, rep)] = values
+ n = len(values)
+ ds = xr.Dataset(
+ {
+ var: xr.DataArray(
+ [sorted_vars[(var, r)] for r in ['Original', 'Clustered']],
+ dims=['representation', 'duration'],
+ coords={'representation': ['Original', 'Clustered'], 'duration': range(n)},
+ )
+ for var in resolved_variables
+ }
+ )
+
+ # Set title based on kind
+ if kind == 'timeseries':
+ title = (
+ 'Original vs Clustered'
+ if len(resolved_variables) > 1
+ else f'Original vs Clustered: {resolved_variables[0]}'
+ )
+ else:
+ title = 'Duration Curve' if len(resolved_variables) > 1 else f'Duration Curve: {resolved_variables[0]}'
+
+ # Use fxplot for smart defaults
+ line_kwargs = {}
+ if line_dash is not None:
+ line_kwargs['line_dash'] = line_dash
+ if line_dash == 'representation':
+ line_kwargs['line_dash_map'] = {'Original': 'dot', 'Clustered': 'solid'}
+
+ fig = ds.fxplot.line(
+ colors=colors,
+ color=color,
+ title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ **line_kwargs,
+ **plotly_kwargs,
+ )
+ fig.update_yaxes(matches=None)
+ fig.for_each_annotation(lambda a: a.update(text=a.text.split('=')[-1]))
+
+ plot_result = PlotResult(data=ds, figure=fig)
+
+ if show is None:
+ show = CONFIG.Plotting.default_show
+ if show:
+ plot_result.show()
+
+ return plot_result
+
+ def _get_time_varying_variables(self) -> list[str]:
+ """Get list of time-varying variables from original data."""
+ result = self._clustering.result
+ if result.original_data is None:
+ return []
+ return [
+ name
+ for name in result.original_data.data_vars
+ if 'time' in result.original_data[name].dims
+ and not np.isclose(result.original_data[name].min(), result.original_data[name].max())
+ ]
+
+ def _resolve_variables(self, variables: str | list[str] | None) -> list[str]:
+ """Resolve variables parameter to a list of valid variable names."""
+ time_vars = self._get_time_varying_variables()
+ if not time_vars:
+ raise ValueError('No time-varying variables found')
+
+ if variables is None:
+ return time_vars
+ elif isinstance(variables, str):
+ if variables not in time_vars:
+ raise ValueError(f"Variable '{variables}' not found. Available: {time_vars}")
+ return [variables]
+ else:
+ invalid = [v for v in variables if v not in time_vars]
+ if invalid:
+ raise ValueError(f'Variables {invalid} not found. Available: {time_vars}')
+ return list(variables)
+
+ def heatmap(
+ self,
+ *,
+ select: SelectType | None = None,
+ colors: str | list[str] | None = None,
+ facet_col: str | None = 'auto',
+ animation_frame: str | None = 'auto',
+ show: bool | None = None,
+ **plotly_kwargs: Any,
+ ) -> PlotResult:
+ """Plot cluster assignments over time as a heatmap timeline.
+
+ Shows which cluster each timestep belongs to as a horizontal color bar.
+ The x-axis is time, color indicates cluster assignment. This visualization
+ aligns with time series data, making it easy to correlate cluster
+ assignments with other plots.
+
+ For multi-period/scenario data, uses faceting and/or animation.
+
+ Args:
+ select: xarray-style selection dict, e.g. {'scenario': 'Base Case'}.
+ colors: Colorscale name (str) or list of colors for heatmap coloring.
+ Dicts are not supported for heatmaps.
+ Defaults to CONFIG.Plotting.default_sequential_colorscale.
+ facet_col: Dimension to facet on columns. 'auto' uses CONFIG priority.
+ animation_frame: Dimension for animation slider. 'auto' uses CONFIG priority.
+ show: Whether to display the figure.
+ Defaults to CONFIG.Plotting.default_show.
+ **plotly_kwargs: Additional arguments passed to plotly.
+
+ Returns:
+ PlotResult containing the heatmap figure and cluster assignment data.
+ The data has 'cluster' variable with time dimension, matching original timesteps.
+ """
+ import pandas as pd
+
+ from ..config import CONFIG
+ from ..plot_result import PlotResult
+ from ..statistics_accessor import _apply_selection
+
+ result = self._clustering.result
+ cs = result.cluster_structure
+ if cs is None:
+ raise ValueError('No cluster structure available')
+
+ cluster_order_da = cs.cluster_order
+ timesteps_per_period = cs.timesteps_per_cluster
+ original_time = result.original_data.coords['time'] if result.original_data is not None else None
+
+ # Apply selection if provided
+ if select:
+ cluster_order_da = _apply_selection(cluster_order_da.to_dataset(name='cluster'), select)['cluster']
+
+ # Check for multi-dimensional data
+ has_periods = 'period' in cluster_order_da.dims
+ has_scenarios = 'scenario' in cluster_order_da.dims
+
+ # Get dimension values
+ periods = list(cluster_order_da.coords['period'].values) if has_periods else [None]
+ scenarios = list(cluster_order_da.coords['scenario'].values) if has_scenarios else [None]
+
+ # Build cluster assignment per timestep for each (period, scenario) slice
+ cluster_slices: dict[tuple, xr.DataArray] = {}
+ for p in periods:
+ for s in scenarios:
+ cluster_order = cs.get_cluster_order_for_slice(period=p, scenario=s)
+ # Expand: each cluster repeated timesteps_per_period times
+ cluster_per_timestep = np.repeat(cluster_order, timesteps_per_period)
+ cluster_slices[(p, s)] = xr.DataArray(
+ cluster_per_timestep,
+ dims=['time'],
+ coords={'time': original_time} if original_time is not None else None,
+ )
+
+ # Combine slices into multi-dimensional DataArray
+ if has_periods and has_scenarios:
+ period_arrays = []
+ for p in periods:
+ scenario_arrays = [cluster_slices[(p, s)] for s in scenarios]
+ period_arrays.append(xr.concat(scenario_arrays, dim=pd.Index(scenarios, name='scenario')))
+ cluster_da = xr.concat(period_arrays, dim=pd.Index(periods, name='period'))
+ elif has_periods:
+ cluster_da = xr.concat(
+ [cluster_slices[(p, None)] for p in periods],
+ dim=pd.Index(periods, name='period'),
+ )
+ elif has_scenarios:
+ cluster_da = xr.concat(
+ [cluster_slices[(None, s)] for s in scenarios],
+ dim=pd.Index(scenarios, name='scenario'),
+ )
+ else:
+ cluster_da = cluster_slices[(None, None)]
+
+ # Add dummy y dimension for heatmap visualization (single row)
+ heatmap_da = cluster_da.expand_dims('y', axis=-1)
+ heatmap_da = heatmap_da.assign_coords(y=['Cluster'])
+ heatmap_da.name = 'cluster_assignment'
+
+ # Reorder dims so 'time' and 'y' are first (heatmap x/y axes)
+ # Other dims (period, scenario) will be used for faceting/animation
+ target_order = ['time', 'y'] + [d for d in heatmap_da.dims if d not in ('time', 'y')]
+ heatmap_da = heatmap_da.transpose(*target_order)
+
+ # Use fxplot.heatmap for smart defaults
+ fig = heatmap_da.fxplot.heatmap(
+ colors=colors,
+ title='Cluster Assignments',
+ facet_col=facet_col,
+ animation_frame=animation_frame,
+ aspect='auto',
+ **plotly_kwargs,
+ )
+
+ # Clean up: hide y-axis since it's just a single row
+ fig.update_yaxes(showticklabels=False)
+ fig.for_each_annotation(lambda a: a.update(text=a.text.split('=')[-1]))
+
+ # Data is exactly what we plotted (without dummy y dimension)
+ cluster_da.name = 'cluster'
+ data = xr.Dataset({'cluster': cluster_da})
+ plot_result = PlotResult(data=data, figure=fig)
+
+ if show is None:
+ show = CONFIG.Plotting.default_show
+ if show:
+ plot_result.show()
+
+ return plot_result
+
+ def clusters(
+ self,
+ variables: str | list[str] | None = None,
+ *,
+ select: SelectType | None = None,
+ colors: ColorType | None = None,
+ color: str | None = 'auto',
+ facet_col: str | None = 'cluster',
+ facet_cols: int | None = None,
+ show: bool | None = None,
+ **plotly_kwargs: Any,
+ ) -> PlotResult:
+ """Plot each cluster's typical period profile.
+
+ Shows each cluster as a separate faceted subplot with all variables
+ colored differently. Useful for understanding what each cluster represents.
+
+ Args:
+ variables: Variable(s) to plot. Can be a string, list of strings,
+ or None to plot all time-varying variables.
+ select: xarray-style selection dict, e.g. {'scenario': 'Base Case'}.
+ colors: Color specification (colorscale name, color list, or label-to-color dict).
+ color: Dimension for line colors. 'auto' uses CONFIG priority (typically 'variable').
+ Use 'cluster' to color by cluster instead of faceting.
+ facet_col: Dimension for subplot columns. Defaults to 'cluster'.
+ Use 'variable' to facet by variable instead.
+ facet_cols: Max columns before wrapping facets.
+ Defaults to CONFIG.Plotting.default_facet_cols.
+ show: Whether to display the figure.
+ Defaults to CONFIG.Plotting.default_show.
+ **plotly_kwargs: Additional arguments passed to plotly.
+
+ Returns:
+ PlotResult containing the figure and underlying data.
+ """
+ from ..config import CONFIG
+ from ..plot_result import PlotResult
+ from ..statistics_accessor import _apply_selection
+
+ result = self._clustering.result
+ cs = result.cluster_structure
+ if result.aggregated_data is None or cs is None:
+ raise ValueError('No aggregated data or cluster structure available')
+
+ # Apply selection to aggregated data
+ aggregated_data = _apply_selection(result.aggregated_data, select)
+
+ time_vars = self._get_time_varying_variables()
+ if not time_vars:
+ raise ValueError('No time-varying variables found')
+
+ # Resolve variables
+ resolved_variables = self._resolve_variables(variables)
+
+ n_clusters = int(cs.n_clusters) if isinstance(cs.n_clusters, (int, np.integer)) else int(cs.n_clusters.values)
+ timesteps_per_cluster = cs.timesteps_per_cluster
+
+ # Build Dataset with cluster dimension, using labels with occurrence counts
+ cluster_labels = [
+ f'Cluster {c} (Γ{int(cs.cluster_occurrences.sel(cluster=c).values)})' for c in range(n_clusters)
+ ]
+
+ data_vars = {}
+ for var in resolved_variables:
+ data = aggregated_data[var].values
+ data_by_cluster = data.reshape(n_clusters, timesteps_per_cluster)
+ data_vars[var] = xr.DataArray(
+ data_by_cluster,
+ dims=['cluster', 'time'],
+ coords={'cluster': cluster_labels, 'time': range(timesteps_per_cluster)},
+ )
+
+ ds = xr.Dataset(data_vars)
+ title = 'Clusters' if len(resolved_variables) > 1 else f'Clusters: {resolved_variables[0]}'
+
+ # Use fxplot for smart defaults
+ fig = ds.fxplot.line(
+ colors=colors,
+ color=color,
+ title=title,
+ facet_col=facet_col,
+ facet_cols=facet_cols,
+ **plotly_kwargs,
+ )
+ fig.update_yaxes(matches=None)
+ fig.for_each_annotation(lambda a: a.update(text=a.text.split('=')[-1]))
+
+ # Include occurrences in result data
+ data_vars['occurrences'] = cs.cluster_occurrences
+ result_data = xr.Dataset(data_vars)
+ plot_result = PlotResult(data=result_data, figure=fig)
+
+ if show is None:
+ show = CONFIG.Plotting.default_show
+ if show:
+ plot_result.show()
+
+ return plot_result
+
+
+@dataclass
+class Clustering:
+ """Information about an aggregation stored on a FlowSystem.
+
+ This is stored on the FlowSystem after aggregation to enable:
+ - expand_solution() to map back to original timesteps
+ - Statistics to properly weight results
+ - Inter-cluster storage linking
+ - Serialization/deserialization of aggregated models
+
+ Attributes:
+ result: The ClusterResult from the aggregation backend.
+ backend_name: Name of the aggregation backend used (e.g., 'tsam', 'manual').
+ metrics: Clustering quality metrics (RMSE, MAE, etc.) as xr.Dataset.
+ Each metric (e.g., 'RMSE', 'MAE') is a DataArray with dims
+ ``[time_series, period?, scenario?]``.
+
+ Example:
+ >>> fs_clustered = flow_system.transform.cluster(n_clusters=8, cluster_duration='1D')
+ >>> fs_clustered.clustering.n_clusters
+ 8
+ >>> fs_clustered.clustering.plot.compare()
+ >>> fs_clustered.clustering.plot.heatmap()
+ """
+
+ result: ClusterResult
+ backend_name: str = 'unknown'
+ metrics: xr.Dataset | None = None
+
+ def _create_reference_structure(self) -> tuple[dict, dict[str, xr.DataArray]]:
+ """Create reference structure for serialization."""
+ ref = {'__class__': self.__class__.__name__}
+ arrays = {}
+
+ # Store nested ClusterResult
+ result_ref, result_arrays = self.result._create_reference_structure()
+ ref['result'] = result_ref
+ arrays.update(result_arrays)
+
+ # Store scalar values
+ ref['backend_name'] = self.backend_name
+
+ return ref, arrays
+
+ def __repr__(self) -> str:
+ cs = self.result.cluster_structure
+ if cs is not None:
+ n_clusters = (
+ int(cs.n_clusters) if isinstance(cs.n_clusters, (int, np.integer)) else int(cs.n_clusters.values)
+ )
+ structure_info = f'{cs.n_original_clusters} periods β {n_clusters} clusters'
+ else:
+ structure_info = 'no structure'
+ return f'Clustering(\n backend={self.backend_name!r}\n {structure_info}\n)'
+
+ @property
+ def plot(self) -> ClusteringPlotAccessor:
+ """Access plotting methods for clustering visualization.
+
+ Returns:
+ ClusteringPlotAccessor with compare(), heatmap(), and clusters() methods.
+
+ Example:
+ >>> fs.clustering.plot.compare() # timeseries comparison
+ >>> fs.clustering.plot.compare(kind='duration_curve') # duration curve
+ >>> fs.clustering.plot.heatmap() # structure visualization
+ >>> fs.clustering.plot.clusters() # cluster profiles
+ """
+ return ClusteringPlotAccessor(self)
+
+ # Convenience properties delegating to nested objects
+
+ @property
+ def cluster_order(self) -> xr.DataArray:
+ """Which cluster each original period belongs to."""
+ if self.result.cluster_structure is None:
+ raise ValueError('No cluster_structure available')
+ return self.result.cluster_structure.cluster_order
+
+ @property
+ def occurrences(self) -> xr.DataArray:
+ """How many original periods each cluster represents."""
+ if self.result.cluster_structure is None:
+ raise ValueError('No cluster_structure available')
+ return self.result.cluster_structure.cluster_occurrences
+
+ @property
+ def n_clusters(self) -> int:
+ """Number of clusters."""
+ if self.result.cluster_structure is None:
+ raise ValueError('No cluster_structure available')
+ n = self.result.cluster_structure.n_clusters
+ return int(n) if isinstance(n, (int, np.integer)) else int(n.values)
+
+ @property
+ def n_original_clusters(self) -> int:
+ """Number of original periods (before clustering)."""
+ if self.result.cluster_structure is None:
+ raise ValueError('No cluster_structure available')
+ return self.result.cluster_structure.n_original_clusters
+
+ @property
+ def timesteps_per_period(self) -> int:
+ """Number of timesteps in each period/cluster.
+
+ Alias for :attr:`timesteps_per_cluster`.
+ """
+ return self.timesteps_per_cluster
+
+ @property
+ def timesteps_per_cluster(self) -> int:
+ """Number of timesteps in each cluster."""
+ if self.result.cluster_structure is None:
+ raise ValueError('No cluster_structure available')
+ return self.result.cluster_structure.timesteps_per_cluster
+
+ @property
+ def timestep_mapping(self) -> xr.DataArray:
+ """Mapping from original timesteps to representative timestep indices."""
+ return self.result.timestep_mapping
+
+ @property
+ def cluster_start_positions(self) -> np.ndarray:
+ """Integer positions where clusters start.
+
+ Returns the indices of the first timestep of each cluster.
+ Use these positions to build masks for specific use cases.
+
+ Returns:
+ 1D numpy array of positions: [0, T, 2T, ...] where T = timesteps_per_period.
+
+ Example:
+ For 2 clusters with 24 timesteps each:
+ >>> clustering.cluster_start_positions
+ array([0, 24])
+ """
+ if self.result.cluster_structure is None:
+ raise ValueError('No cluster_structure available')
+
+ n_timesteps = self.n_clusters * self.timesteps_per_period
+ return np.arange(0, n_timesteps, self.timesteps_per_period)
+
+ @property
+ def original_timesteps(self) -> pd.DatetimeIndex:
+ """Original timesteps before clustering.
+
+ Derived from the 'original_time' coordinate of timestep_mapping.
+
+ Raises:
+ KeyError: If 'original_time' coordinate is missing from timestep_mapping.
+ """
+ if 'original_time' not in self.result.timestep_mapping.coords:
+ raise KeyError(
+ "timestep_mapping is missing 'original_time' coordinate. "
+ 'This may indicate corrupted or incompatible clustering results.'
+ )
+ return pd.DatetimeIndex(self.result.timestep_mapping.coords['original_time'].values)
+
+
+def create_cluster_structure_from_mapping(
+ timestep_mapping: xr.DataArray,
+ timesteps_per_cluster: int,
+) -> ClusterStructure:
+ """Create ClusterStructure from a timestep mapping.
+
+ This is a convenience function for creating ClusterStructure when you
+ have the timestep mapping but not the full clustering metadata.
+
+ Args:
+ timestep_mapping: Mapping from original timesteps to representative indices.
+ timesteps_per_cluster: Number of timesteps per cluster period.
+
+ Returns:
+ ClusterStructure derived from the mapping.
+ """
+ n_original = len(timestep_mapping)
+ n_original_clusters = n_original // timesteps_per_cluster
+
+ # Determine cluster order from the mapping
+ # Each original period maps to the cluster of its first timestep
+ cluster_order = []
+ for p in range(n_original_clusters):
+ start_idx = p * timesteps_per_cluster
+ cluster_idx = int(timestep_mapping.isel(original_time=start_idx).values) // timesteps_per_cluster
+ cluster_order.append(cluster_idx)
+
+ cluster_order_da = xr.DataArray(cluster_order, dims=['original_cluster'], name='cluster_order')
+
+ # Count occurrences of each cluster
+ unique_clusters = np.unique(cluster_order)
+ occurrences = {}
+ for c in unique_clusters:
+ occurrences[int(c)] = sum(1 for x in cluster_order if x == c)
+
+ n_clusters = len(unique_clusters)
+ cluster_occurrences_da = xr.DataArray(
+ [occurrences.get(c, 0) for c in range(n_clusters)],
+ dims=['cluster'],
+ name='cluster_occurrences',
+ )
+
+ return ClusterStructure(
+ cluster_order=cluster_order_da,
+ cluster_occurrences=cluster_occurrences_da,
+ n_clusters=n_clusters,
+ timesteps_per_cluster=timesteps_per_cluster,
+ )
+
+
+def _register_clustering_classes():
+ """Register clustering classes for IO.
+
+ Called from flow_system.py after all imports are complete to avoid circular imports.
+ """
+ from ..structure import CLASS_REGISTRY
+
+ CLASS_REGISTRY['ClusterStructure'] = ClusterStructure
+ CLASS_REGISTRY['ClusterResult'] = ClusterResult
+ CLASS_REGISTRY['Clustering'] = Clustering
diff --git a/flixopt/clustering/intercluster_helpers.py b/flixopt/clustering/intercluster_helpers.py
new file mode 100644
index 000000000..a89a80862
--- /dev/null
+++ b/flixopt/clustering/intercluster_helpers.py
@@ -0,0 +1,178 @@
+"""Helper utilities for inter-cluster storage linking.
+
+This module provides utilities for building inter-cluster storage linking
+constraints following the S-N model from Blanke et al. (2022).
+
+Background
+----------
+When time series are clustered (aggregated into representative periods), storage
+behavior needs special handling. The S-N linking model introduces:
+
+- **SOC_boundary**: Absolute state-of-charge at the boundary between original periods.
+ With N original periods, there are N+1 boundary points.
+
+- **Linking**: SOC_boundary[d+1] = SOC_boundary[d] + delta_SOC[cluster_order[d]]
+ Each boundary is connected to the next via the net charge change of the
+ representative cluster for that period.
+
+These utilities help construct the coordinates and bounds for SOC_boundary variables.
+
+References
+----------
+- Blanke, T., et al. (2022). "Inter-Cluster Storage Linking for Time Series
+ Aggregation in Energy System Optimization Models."
+- Kotzur, L., et al. (2018). "Time series aggregation for energy system design:
+ Modeling seasonal storage."
+
+See Also
+--------
+:class:`flixopt.components.InterclusterStorageModel`
+ The storage model that uses these utilities.
+"""
+
+from __future__ import annotations
+
+from dataclasses import dataclass
+from typing import TYPE_CHECKING
+
+import numpy as np
+import xarray as xr
+
+if TYPE_CHECKING:
+ from ..flow_system import FlowSystem
+ from ..interface import InvestParameters
+
+
+@dataclass
+class CapacityBounds:
+ """Bounds for SOC_boundary variable creation.
+
+ This dataclass holds the lower and upper bounds for the SOC_boundary variable,
+ along with a flag indicating whether investment sizing is used.
+
+ Attributes:
+ lower: Lower bound DataArray (typically zeros).
+ upper: Upper bound DataArray (capacity or maximum investment size).
+ has_investment: True if the storage uses InvestParameters for sizing.
+ """
+
+ lower: xr.DataArray
+ upper: xr.DataArray
+ has_investment: bool
+
+
+def extract_capacity_bounds(
+ capacity_param: InvestParameters | int | float | None,
+ boundary_coords: dict,
+ boundary_dims: list[str],
+) -> CapacityBounds:
+ """Extract capacity bounds from storage parameters for SOC_boundary variable.
+
+ This function determines the appropriate bounds for the SOC_boundary variable
+ based on the storage's capacity parameter:
+
+ - **Fixed capacity** (numeric): Upper bound is the fixed value.
+ - **InvestParameters**: Upper bound is maximum_size (or fixed_size if set).
+ The actual bound is enforced via separate constraints linked to investment.size.
+ - **None/Unbounded**: Upper bound is set to a large value (1e9).
+
+ The lower bound is always zero (SOC cannot be negative).
+
+ Args:
+ capacity_param: Storage capacity specification. Can be:
+ - Numeric (int/float): Fixed capacity
+ - InvestParameters: Investment-based sizing with min/max
+ - None: Unbounded storage
+ boundary_coords: Coordinate dictionary for SOC_boundary variable.
+ Must contain 'cluster_boundary' key.
+ boundary_dims: Dimension names for SOC_boundary variable.
+ First dimension must be 'cluster_boundary'.
+
+ Returns:
+ CapacityBounds with lower/upper bounds and investment flag.
+
+ Example:
+ >>> coords, dims = build_boundary_coords(14, flow_system)
+ >>> bounds = extract_capacity_bounds(InvestParameters(maximum_size=10000), coords, dims)
+ >>> bounds.has_investment
+ True
+ >>> bounds.upper.max()
+ 10000.0
+ """
+ n_boundaries = len(boundary_coords['cluster_boundary'])
+ lb_shape = [n_boundaries] + [len(boundary_coords[d]) for d in boundary_dims[1:]]
+
+ lb = xr.DataArray(np.zeros(lb_shape), coords=boundary_coords, dims=boundary_dims)
+
+ # Determine has_investment and cap_value
+ has_investment = hasattr(capacity_param, 'maximum_size')
+
+ if hasattr(capacity_param, 'fixed_size') and capacity_param.fixed_size is not None:
+ cap_value = capacity_param.fixed_size
+ elif hasattr(capacity_param, 'maximum_size') and capacity_param.maximum_size is not None:
+ cap_value = capacity_param.maximum_size
+ elif isinstance(capacity_param, (int, float)):
+ cap_value = capacity_param
+ else:
+ cap_value = 1e9 # Large default for unbounded case
+
+ # Build upper bound
+ if isinstance(cap_value, xr.DataArray) and cap_value.dims:
+ ub = cap_value.expand_dims({'cluster_boundary': n_boundaries}, axis=0)
+ ub = ub.assign_coords(cluster_boundary=np.arange(n_boundaries))
+ ub = ub.transpose('cluster_boundary', ...)
+ else:
+ if hasattr(cap_value, 'item'):
+ cap_value = float(cap_value.item())
+ else:
+ cap_value = float(cap_value)
+ ub = xr.DataArray(np.full(lb_shape, cap_value), coords=boundary_coords, dims=boundary_dims)
+
+ return CapacityBounds(lower=lb, upper=ub, has_investment=has_investment)
+
+
+def build_boundary_coords(
+ n_original_clusters: int,
+ flow_system: FlowSystem,
+) -> tuple[dict, list[str]]:
+ """Build coordinates and dimensions for SOC_boundary variable.
+
+ Creates the coordinate dictionary and dimension list needed to create the
+ SOC_boundary variable. The primary dimension is 'cluster_boundary' with
+ N+1 values (one for each boundary between N original periods).
+
+ Additional dimensions (period, scenario) are included if present in the
+ FlowSystem, ensuring the SOC_boundary variable has the correct shape for
+ multi-period or stochastic optimizations.
+
+ Args:
+ n_original_clusters: Number of original (non-aggregated) time periods.
+ For example, if a year is clustered into 8 typical days but originally
+ had 365 days, this would be 365.
+ flow_system: The FlowSystem containing optional period/scenario dimensions.
+
+ Returns:
+ Tuple of (coords, dims) where:
+ - coords: Dictionary mapping dimension names to coordinate arrays
+ - dims: List of dimension names in order
+
+ Example:
+ >>> coords, dims = build_boundary_coords(14, flow_system)
+ >>> dims
+ ['cluster_boundary'] # or ['cluster_boundary', 'period'] if periods exist
+ >>> coords['cluster_boundary']
+ array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14])
+ """
+ n_boundaries = n_original_clusters + 1
+ coords = {'cluster_boundary': np.arange(n_boundaries)}
+ dims = ['cluster_boundary']
+
+ if flow_system.periods is not None:
+ dims.append('period')
+ coords['period'] = np.array(list(flow_system.periods))
+
+ if flow_system.scenarios is not None:
+ dims.append('scenario')
+ coords['scenario'] = np.array(list(flow_system.scenarios))
+
+ return coords, dims
diff --git a/flixopt/comparison.py b/flixopt/comparison.py
new file mode 100644
index 000000000..63a00a0f1
--- /dev/null
+++ b/flixopt/comparison.py
@@ -0,0 +1,609 @@
+"""Compare multiple FlowSystems side-by-side."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+import xarray as xr
+
+from .config import CONFIG
+from .plot_result import PlotResult
+
+if TYPE_CHECKING:
+ from .flow_system import FlowSystem
+
+__all__ = ['Comparison']
+
+# Type aliases (matching statistics_accessor.py)
+SelectType = dict[str, Any]
+FilterType = str | list[str]
+ColorType = str | list[str] | dict[str, str] | None
+
+
+class Comparison:
+ """Compare multiple FlowSystems side-by-side.
+
+ Combines solutions and statistics from multiple FlowSystems into unified
+ xarray Datasets with a 'case' dimension. The existing plotting infrastructure
+ automatically handles faceting by the 'case' dimension.
+
+ All FlowSystems must have matching dimensions (time, period, scenario, etc.).
+ Use `flow_system.transform.sel()` to align dimensions before comparing.
+
+ Args:
+ flow_systems: List of FlowSystems to compare. All must be optimized
+ and have matching dimensions.
+ names: Optional names for each case. If None, uses FlowSystem.name.
+
+ Raises:
+ ValueError: If FlowSystems have mismatched dimensions.
+ RuntimeError: If any FlowSystem has no solution.
+
+ Examples:
+ ```python
+ # Compare two systems (uses FlowSystem.name by default)
+ comp = fx.Comparison([fs_base, fs_modified])
+
+ # Or with custom names
+ comp = fx.Comparison([fs_base, fs_modified], names=['baseline', 'modified'])
+
+ # Side-by-side plots (auto-facets by 'case')
+ comp.statistics.plot.balance('Heat')
+ comp.statistics.flow_rates.fxplot.line()
+
+ # Access combined data
+ comp.solution # xr.Dataset with 'case' dimension
+ comp.statistics.flow_rates # xr.Dataset with 'case' dimension
+
+ # Compute differences relative to first case
+ comp.diff() # Returns xr.Dataset of differences
+ comp.diff('baseline') # Or specify reference by name
+
+ # For systems with different dimensions, align first:
+ fs_both = ... # Has scenario dimension
+ fs_mild = fs_both.transform.sel(scenario='Mild') # Select one scenario
+ fs_other = ... # Also select to match
+ comp = fx.Comparison([fs_mild, fs_other]) # Now dimensions match
+ ```
+ """
+
+ def __init__(self, flow_systems: list[FlowSystem], names: list[str] | None = None) -> None:
+ if len(flow_systems) < 2:
+ raise ValueError('Comparison requires at least 2 FlowSystems')
+
+ self._systems = flow_systems
+ self._names = names or [fs.name or f'System {i}' for i, fs in enumerate(flow_systems)]
+
+ if len(self._names) != len(self._systems):
+ raise ValueError(
+ f'Number of names ({len(self._names)}) must match number of FlowSystems ({len(self._systems)})'
+ )
+
+ if len(set(self._names)) != len(self._names):
+ raise ValueError(f'Case names must be unique, got: {self._names}')
+
+ # Validate all FlowSystems have solutions
+ for fs in flow_systems:
+ if fs.solution is None:
+ raise RuntimeError(f"FlowSystem '{fs.name}' has no solution. Run optimize() first.")
+
+ # Validate matching dimensions across all FlowSystems
+ self._validate_matching_dimensions()
+
+ # Caches
+ self._solution: xr.Dataset | None = None
+ self._statistics: ComparisonStatistics | None = None
+
+ # Core dimensions that must match across FlowSystems
+ # Note: 'cluster' and 'cluster_boundary' are auxiliary dimensions from clustering
+ _CORE_DIMS = {'time', 'period', 'scenario'}
+
+ def _validate_matching_dimensions(self) -> None:
+ """Validate that all FlowSystems have matching core dimensions.
+
+ Only validates core dimensions (time, period, scenario). Auxiliary
+ dimensions like 'cluster_boundary' are ignored as they don't affect
+ the comparison logic.
+ """
+ reference = self._systems[0]
+ ref_core_dims = set(reference.solution.dims) & self._CORE_DIMS
+ ref_name = self._names[0]
+
+ for fs, name in zip(self._systems[1:], self._names[1:], strict=True):
+ fs_core_dims = set(fs.solution.dims) & self._CORE_DIMS
+ if fs_core_dims != ref_core_dims:
+ missing = ref_core_dims - fs_core_dims
+ extra = fs_core_dims - ref_core_dims
+ msg_parts = [f"Core dimension mismatch between '{ref_name}' and '{name}'."]
+ if missing:
+ msg_parts.append(f"Missing in '{name}': {missing}.")
+ if extra:
+ msg_parts.append(f"Extra in '{name}': {extra}.")
+ msg_parts.append('Use .transform.sel() to align dimensions before comparing.')
+ raise ValueError(' '.join(msg_parts))
+
+ @property
+ def names(self) -> list[str]:
+ """Case names for each FlowSystem."""
+ return self._names
+
+ @property
+ def solution(self) -> xr.Dataset:
+ """Combined solution Dataset with 'case' dimension."""
+ if self._solution is None:
+ datasets = []
+ for fs, name in zip(self._systems, self._names, strict=True):
+ ds = fs.solution.expand_dims(case=[name])
+ datasets.append(ds)
+ self._solution = xr.concat(datasets, dim='case', join='outer', fill_value=float('nan'))
+ return self._solution
+
+ @property
+ def statistics(self) -> ComparisonStatistics:
+ """Combined statistics accessor with 'case' dimension."""
+ if self._statistics is None:
+ self._statistics = ComparisonStatistics(self)
+ return self._statistics
+
+ def diff(self, reference: str | int = 0) -> xr.Dataset:
+ """Compute differences relative to a reference case.
+
+ Args:
+ reference: Reference case name or index (default: 0, first case).
+
+ Returns:
+ Dataset with differences (each case minus reference).
+ """
+ if isinstance(reference, str):
+ if reference not in self._names:
+ raise ValueError(f"Reference '{reference}' not found. Available: {self._names}")
+ ref_idx = self._names.index(reference)
+ else:
+ ref_idx = reference
+
+ ref_data = self.solution.isel(case=ref_idx)
+ return self.solution - ref_data
+
+
+class ComparisonStatistics:
+ """Combined statistics accessor for comparing FlowSystems.
+
+ Mirrors StatisticsAccessor properties, concatenating data with a 'case' dimension.
+ Access via ``Comparison.statistics``.
+ """
+
+ def __init__(self, comparison: Comparison) -> None:
+ self._comp = comparison
+ # Caches for dataset properties
+ self._flow_rates: xr.Dataset | None = None
+ self._flow_hours: xr.Dataset | None = None
+ self._flow_sizes: xr.Dataset | None = None
+ self._storage_sizes: xr.Dataset | None = None
+ self._sizes: xr.Dataset | None = None
+ self._charge_states: xr.Dataset | None = None
+ self._temporal_effects: xr.Dataset | None = None
+ self._periodic_effects: xr.Dataset | None = None
+ self._total_effects: xr.Dataset | None = None
+ # Caches for dict properties
+ self._carrier_colors: dict[str, str] | None = None
+ self._component_colors: dict[str, str] | None = None
+ self._bus_colors: dict[str, str] | None = None
+ self._carrier_units: dict[str, str] | None = None
+ self._effect_units: dict[str, str] | None = None
+ # Plot accessor
+ self._plot: ComparisonStatisticsPlot | None = None
+
+ def _concat_property(self, prop_name: str) -> xr.Dataset:
+ """Concatenate a statistics property across all cases."""
+ datasets = []
+ for fs, name in zip(self._comp._systems, self._comp._names, strict=True):
+ ds = getattr(fs.statistics, prop_name)
+ datasets.append(ds.expand_dims(case=[name]))
+ return xr.concat(datasets, dim='case', join='outer', fill_value=float('nan'))
+
+ def _merge_dict_property(self, prop_name: str) -> dict[str, str]:
+ """Merge a dict property from all cases (later cases override)."""
+ result: dict[str, str] = {}
+ for fs in self._comp._systems:
+ result.update(getattr(fs.statistics, prop_name))
+ return result
+
+ @property
+ def flow_rates(self) -> xr.Dataset:
+ """Combined flow rates with 'case' dimension."""
+ if self._flow_rates is None:
+ self._flow_rates = self._concat_property('flow_rates')
+ return self._flow_rates
+
+ @property
+ def flow_hours(self) -> xr.Dataset:
+ """Combined flow hours (energy) with 'case' dimension."""
+ if self._flow_hours is None:
+ self._flow_hours = self._concat_property('flow_hours')
+ return self._flow_hours
+
+ @property
+ def flow_sizes(self) -> xr.Dataset:
+ """Combined flow investment sizes with 'case' dimension."""
+ if self._flow_sizes is None:
+ self._flow_sizes = self._concat_property('flow_sizes')
+ return self._flow_sizes
+
+ @property
+ def storage_sizes(self) -> xr.Dataset:
+ """Combined storage capacity sizes with 'case' dimension."""
+ if self._storage_sizes is None:
+ self._storage_sizes = self._concat_property('storage_sizes')
+ return self._storage_sizes
+
+ @property
+ def sizes(self) -> xr.Dataset:
+ """Combined sizes (flow + storage) with 'case' dimension."""
+ if self._sizes is None:
+ self._sizes = self._concat_property('sizes')
+ return self._sizes
+
+ @property
+ def charge_states(self) -> xr.Dataset:
+ """Combined storage charge states with 'case' dimension."""
+ if self._charge_states is None:
+ self._charge_states = self._concat_property('charge_states')
+ return self._charge_states
+
+ @property
+ def temporal_effects(self) -> xr.Dataset:
+ """Combined temporal effects with 'case' dimension."""
+ if self._temporal_effects is None:
+ self._temporal_effects = self._concat_property('temporal_effects')
+ return self._temporal_effects
+
+ @property
+ def periodic_effects(self) -> xr.Dataset:
+ """Combined periodic effects with 'case' dimension."""
+ if self._periodic_effects is None:
+ self._periodic_effects = self._concat_property('periodic_effects')
+ return self._periodic_effects
+
+ @property
+ def total_effects(self) -> xr.Dataset:
+ """Combined total effects with 'case' dimension."""
+ if self._total_effects is None:
+ self._total_effects = self._concat_property('total_effects')
+ return self._total_effects
+
+ @property
+ def carrier_colors(self) -> dict[str, str]:
+ """Merged carrier colors from all cases."""
+ if self._carrier_colors is None:
+ self._carrier_colors = self._merge_dict_property('carrier_colors')
+ return self._carrier_colors
+
+ @property
+ def component_colors(self) -> dict[str, str]:
+ """Merged component colors from all cases."""
+ if self._component_colors is None:
+ self._component_colors = self._merge_dict_property('component_colors')
+ return self._component_colors
+
+ @property
+ def bus_colors(self) -> dict[str, str]:
+ """Merged bus colors from all cases."""
+ if self._bus_colors is None:
+ self._bus_colors = self._merge_dict_property('bus_colors')
+ return self._bus_colors
+
+ @property
+ def carrier_units(self) -> dict[str, str]:
+ """Merged carrier units from all cases."""
+ if self._carrier_units is None:
+ self._carrier_units = self._merge_dict_property('carrier_units')
+ return self._carrier_units
+
+ @property
+ def effect_units(self) -> dict[str, str]:
+ """Merged effect units from all cases."""
+ if self._effect_units is None:
+ self._effect_units = self._merge_dict_property('effect_units')
+ return self._effect_units
+
+ @property
+ def plot(self) -> ComparisonStatisticsPlot:
+ """Access plot methods for comparison statistics."""
+ if self._plot is None:
+ self._plot = ComparisonStatisticsPlot(self)
+ return self._plot
+
+
+class ComparisonStatisticsPlot:
+ """Plot accessor for comparison statistics.
+
+ Wraps StatisticsPlotAccessor methods, combining data from all FlowSystems
+ with a 'case' dimension for faceting.
+ """
+
+ # Data-related kwargs for each method (everything else is plotly kwargs)
+ _DATA_KWARGS: dict[str, set[str]] = {
+ 'balance': {'select', 'include', 'exclude', 'unit'},
+ 'carrier_balance': {'select', 'include', 'exclude', 'unit'},
+ 'flows': {'start', 'end', 'component', 'select', 'unit'},
+ 'storage': {'select', 'unit', 'charge_state_color'},
+ 'charge_states': {'select'},
+ 'duration_curve': {'select', 'normalize'},
+ 'sizes': {'max_size', 'select'},
+ 'effects': {'effect', 'by', 'select'},
+ 'heatmap': {'select', 'reshape'},
+ }
+
+ def __init__(self, statistics: ComparisonStatistics) -> None:
+ self._stats = statistics
+ self._comp = statistics._comp
+
+ def _split_kwargs(self, method_name: str, kwargs: dict) -> tuple[dict, dict]:
+ """Split kwargs into data kwargs and plotly kwargs."""
+ data_keys = self._DATA_KWARGS.get(method_name, set())
+ data_kwargs = {k: v for k, v in kwargs.items() if k in data_keys}
+ plotly_kwargs = {k: v for k, v in kwargs.items() if k not in data_keys}
+ return data_kwargs, plotly_kwargs
+
+ def _combine_data(self, method_name: str, *args, **kwargs) -> tuple[xr.Dataset, str]:
+ """Call plot method on each system and combine data. Returns (combined_data, title)."""
+ datasets = []
+ title = ''
+ kwargs = {**kwargs, 'show': False} # Don't mutate original
+
+ for fs, case_name in zip(self._comp._systems, self._comp._names, strict=True):
+ try:
+ result = getattr(fs.statistics.plot, method_name)(*args, **kwargs)
+ datasets.append(result.data.expand_dims(case=[case_name]))
+ title = result.figure.layout.title.text or title
+ except (KeyError, ValueError):
+ continue
+
+ if not datasets:
+ return xr.Dataset(), ''
+
+ return xr.concat(datasets, dim='case', join='outer', fill_value=float('nan')), title
+
+ def _finalize(self, ds: xr.Dataset, fig, show: bool | None) -> PlotResult:
+ """Handle show and return PlotResult."""
+ import plotly.graph_objects as go
+
+ if show is None:
+ show = CONFIG.Plotting.default_show
+ if show and fig:
+ fig.show()
+ return PlotResult(data=ds, figure=fig or go.Figure())
+
+ def balance(
+ self,
+ node: str,
+ *,
+ colors=None,
+ facet_col='auto',
+ facet_row='auto',
+ animation_frame='auto',
+ show: bool | None = None,
+ **kwargs,
+ ) -> PlotResult:
+ """Plot node balance comparison. See StatisticsPlotAccessor.balance."""
+ data_kw, plotly_kw = self._split_kwargs('balance', kwargs)
+ ds, title = self._combine_data('balance', node, **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+ fig = ds.fxplot.stacked_bar(
+ colors=colors,
+ title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ **plotly_kw,
+ )
+ return self._finalize(ds, fig, show)
+
+ def carrier_balance(
+ self,
+ carrier: str,
+ *,
+ colors=None,
+ facet_col='auto',
+ facet_row='auto',
+ animation_frame='auto',
+ show: bool | None = None,
+ **kwargs,
+ ) -> PlotResult:
+ """Plot carrier balance comparison. See StatisticsPlotAccessor.carrier_balance."""
+ data_kw, plotly_kw = self._split_kwargs('carrier_balance', kwargs)
+ ds, title = self._combine_data('carrier_balance', carrier, **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+ fig = ds.fxplot.stacked_bar(
+ colors=colors,
+ title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ **plotly_kw,
+ )
+ return self._finalize(ds, fig, show)
+
+ def flows(
+ self,
+ *,
+ colors=None,
+ facet_col='auto',
+ facet_row='auto',
+ animation_frame='auto',
+ show: bool | None = None,
+ **kwargs,
+ ) -> PlotResult:
+ """Plot flows comparison. See StatisticsPlotAccessor.flows."""
+ data_kw, plotly_kw = self._split_kwargs('flows', kwargs)
+ ds, title = self._combine_data('flows', **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+ fig = ds.fxplot.line(
+ colors=colors,
+ title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ **plotly_kw,
+ )
+ return self._finalize(ds, fig, show)
+
+ def storage(
+ self,
+ storage: str,
+ *,
+ colors=None,
+ facet_col='auto',
+ facet_row='auto',
+ animation_frame='auto',
+ show: bool | None = None,
+ **kwargs,
+ ) -> PlotResult:
+ """Plot storage operation comparison. See StatisticsPlotAccessor.storage."""
+ data_kw, plotly_kw = self._split_kwargs('storage', kwargs)
+ ds, title = self._combine_data('storage', storage, **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+ fig = ds.fxplot.stacked_bar(
+ colors=colors,
+ title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ **plotly_kw,
+ )
+ return self._finalize(ds, fig, show)
+
+ def charge_states(
+ self,
+ storages=None,
+ *,
+ colors=None,
+ facet_col='auto',
+ facet_row='auto',
+ animation_frame='auto',
+ show: bool | None = None,
+ **kwargs,
+ ) -> PlotResult:
+ """Plot charge states comparison. See StatisticsPlotAccessor.charge_states."""
+ data_kw, plotly_kw = self._split_kwargs('charge_states', kwargs)
+ ds, title = self._combine_data('charge_states', storages, **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+ fig = ds.fxplot.line(
+ colors=colors,
+ title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ **plotly_kw,
+ )
+ fig.update_yaxes(title_text='Charge State')
+ return self._finalize(ds, fig, show)
+
+ def duration_curve(
+ self,
+ variables,
+ *,
+ normalize: bool = False,
+ colors=None,
+ facet_col='auto',
+ facet_row='auto',
+ animation_frame='auto',
+ show: bool | None = None,
+ **kwargs,
+ ) -> PlotResult:
+ """Plot duration curves comparison. See StatisticsPlotAccessor.duration_curve."""
+ data_kw, plotly_kw = self._split_kwargs('duration_curve', kwargs)
+ ds, title = self._combine_data('duration_curve', variables, normalize=normalize, **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+ fig = ds.fxplot.line(
+ colors=colors,
+ title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ **plotly_kw,
+ )
+ fig.update_xaxes(title_text='Duration [%]' if normalize else 'Timesteps')
+ return self._finalize(ds, fig, show)
+
+ def sizes(
+ self,
+ *,
+ colors=None,
+ facet_col='auto',
+ facet_row='auto',
+ animation_frame='auto',
+ show: bool | None = None,
+ **kwargs,
+ ) -> PlotResult:
+ """Plot investment sizes comparison. See StatisticsPlotAccessor.sizes."""
+ data_kw, plotly_kw = self._split_kwargs('sizes', kwargs)
+ ds, title = self._combine_data('sizes', **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+ fig = ds.fxplot.bar(
+ x='variable',
+ color='variable',
+ colors=colors,
+ title=title,
+ ylabel='Size',
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ **plotly_kw,
+ )
+ return self._finalize(ds, fig, show)
+
+ def effects(
+ self,
+ aspect='total',
+ *,
+ colors=None,
+ facet_col='auto',
+ facet_row='auto',
+ animation_frame='auto',
+ show: bool | None = None,
+ **kwargs,
+ ) -> PlotResult:
+ """Plot effects comparison. See StatisticsPlotAccessor.effects."""
+ data_kw, plotly_kw = self._split_kwargs('effects', kwargs)
+ ds, title = self._combine_data('effects', aspect, **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+
+ by = data_kw.get('by')
+ # After to_dataset(dim='effect'), effects become variables -> 'variable' column
+ x_col = by if by else 'variable'
+ color_col = 'variable' if len(ds.data_vars) > 1 else x_col
+
+ fig = ds.fxplot.bar(
+ x=x_col,
+ color=color_col,
+ colors=colors,
+ title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ **plotly_kw,
+ )
+ fig.update_layout(bargap=0, bargroupgap=0)
+ fig.update_traces(marker_line_width=0)
+ return self._finalize(ds, fig, show)
+
+ def heatmap(
+ self, variables, *, colors=None, facet_col='auto', animation_frame='auto', show: bool | None = None, **kwargs
+ ) -> PlotResult:
+ """Plot heatmap comparison. See StatisticsPlotAccessor.heatmap."""
+ data_kw, plotly_kw = self._split_kwargs('heatmap', kwargs)
+ ds, _ = self._combine_data('heatmap', variables, **data_kw)
+ if not ds.data_vars:
+ return self._finalize(ds, None, show)
+ da = ds[next(iter(ds.data_vars))]
+ fig = da.fxplot.heatmap(colors=colors, facet_col=facet_col, animation_frame=animation_frame, **plotly_kw)
+ return self._finalize(ds, fig, show)
diff --git a/flixopt/components.py b/flixopt/components.py
index 267c144af..e962791d8 100644
--- a/flixopt/components.py
+++ b/flixopt/components.py
@@ -5,6 +5,7 @@
from __future__ import annotations
import logging
+import warnings
from typing import TYPE_CHECKING, Literal
import numpy as np
@@ -270,7 +271,7 @@ class Storage(Component):
maximum_size (or fixed_size) must be explicitly set for proper model scaling.
relative_minimum_charge_state: Minimum charge state (0-1). Default: 0.
relative_maximum_charge_state: Maximum charge state (0-1). Default: 1.
- initial_charge_state: Charge at start. Numeric or 'equals_final'. Default: 0.
+ initial_charge_state: Charge at start. Numeric, 'equals_final', or None (free). Default: 0.
minimal_final_charge_state: Minimum absolute charge required at end (optional).
maximal_final_charge_state: Maximum absolute charge allowed at end (optional).
relative_minimum_final_charge_state: Minimum relative charge at end.
@@ -282,6 +283,21 @@ class Storage(Component):
relative_loss_per_hour: Self-discharge per hour (0-0.1). Default: 0.
prevent_simultaneous_charge_and_discharge: Prevent charging and discharging
simultaneously. Adds binary variables. Default: True.
+ cluster_mode: How this storage is treated during clustering optimization.
+ Only relevant when using ``transform.cluster()``. Options:
+
+ - ``'independent'``: Clusters are fully decoupled. No constraints between
+ clusters, each cluster has free start/end SOC. Fast but ignores
+ seasonal storage value.
+ - ``'cyclic'``: Each cluster is self-contained. The SOC at the start of
+ each cluster equals its end (cluster returns to initial state).
+ Good for "average day" modeling.
+ - ``'intercluster'``: Link storage state across the original timeline using
+ SOC boundary variables (Kotzur et al. approach). Properly values
+ seasonal storage patterns. Overall SOC can drift.
+ - ``'intercluster_cyclic'`` (default): Like 'intercluster' but also enforces
+ that overall SOC returns to initial state (yearly cyclic).
+
meta_data: Additional information stored in results. Python native types only.
Examples:
@@ -388,7 +404,7 @@ def __init__(
capacity_in_flow_hours: Numeric_PS | InvestParameters | None = None,
relative_minimum_charge_state: Numeric_TPS = 0,
relative_maximum_charge_state: Numeric_TPS = 1,
- initial_charge_state: Numeric_PS | Literal['equals_final'] = 0,
+ initial_charge_state: Numeric_PS | Literal['equals_final'] | None = 0,
minimal_final_charge_state: Numeric_PS | None = None,
maximal_final_charge_state: Numeric_PS | None = None,
relative_minimum_final_charge_state: Numeric_PS | None = None,
@@ -398,6 +414,7 @@ def __init__(
relative_loss_per_hour: Numeric_TPS = 0,
prevent_simultaneous_charge_and_discharge: bool = True,
balanced: bool = False,
+ cluster_mode: Literal['independent', 'cyclic', 'intercluster', 'intercluster_cyclic'] = 'intercluster_cyclic',
meta_data: dict | None = None,
):
# TODO: fixed_relative_chargeState implementieren
@@ -427,10 +444,35 @@ def __init__(
self.relative_loss_per_hour: Numeric_TPS = relative_loss_per_hour
self.prevent_simultaneous_charge_and_discharge = prevent_simultaneous_charge_and_discharge
self.balanced = balanced
+ self.cluster_mode = cluster_mode
def create_model(self, model: FlowSystemModel) -> StorageModel:
+ """Create the appropriate storage model based on cluster_mode and flow system state.
+
+ For intercluster modes ('intercluster', 'intercluster_cyclic'), uses
+ :class:`InterclusterStorageModel` which implements S-N linking.
+ For other modes, uses the base :class:`StorageModel`.
+
+ Args:
+ model: The FlowSystemModel to add constraints to.
+
+ Returns:
+ StorageModel or InterclusterStorageModel instance.
+ """
self._plausibility_checks()
- self.submodel = StorageModel(model, self)
+
+ # Use InterclusterStorageModel for intercluster modes when clustering is active
+ clustering = model.flow_system.clustering
+ is_intercluster = clustering is not None and self.cluster_mode in (
+ 'intercluster',
+ 'intercluster_cyclic',
+ )
+
+ if is_intercluster:
+ self.submodel = InterclusterStorageModel(model, self)
+ else:
+ self.submodel = StorageModel(model, self)
+
return self.submodel
def link_to_flow_system(self, flow_system, prefix: str = '') -> None:
@@ -452,7 +494,7 @@ def transform_data(self) -> None:
self.relative_loss_per_hour = self._fit_coords(
f'{self.prefix}|relative_loss_per_hour', self.relative_loss_per_hour
)
- if not isinstance(self.initial_charge_state, str):
+ if self.initial_charge_state is not None and not isinstance(self.initial_charge_state, str):
self.initial_charge_state = self._fit_coords(
f'{self.prefix}|initial_charge_state', self.initial_charge_state, dims=['period', 'scenario']
)
@@ -531,8 +573,8 @@ def _plausibility_checks(self) -> None:
min_initial_at_max_capacity = maximum_capacity * self.relative_minimum_charge_state.isel(time=0)
max_initial_at_min_capacity = minimum_capacity * self.relative_maximum_charge_state.isel(time=0)
- # Only perform numeric comparisons if not using 'equals_final'
- if not initial_equals_final:
+ # Only perform numeric comparisons if using a numeric initial_charge_state
+ if not initial_equals_final and self.initial_charge_state is not None:
if (self.initial_charge_state > max_initial_at_min_capacity).any():
raise PlausibilityError(
f'{self.label_full}: {self.initial_charge_state=} '
@@ -868,6 +910,10 @@ class StorageModel(ComponentModel):
Mathematical Formulation:
See
+
+ Note:
+ This class uses a template method pattern. Subclasses (e.g., InterclusterStorageModel)
+ can override individual methods to customize behavior without duplicating code.
"""
element: Storage
@@ -876,10 +922,18 @@ def __init__(self, model: FlowSystemModel, element: Storage):
super().__init__(model, element)
def _do_modeling(self):
- """Create charge state variables, energy balance equations, and optional investment submodels"""
+ """Create charge state variables, energy balance equations, and optional investment submodels."""
super()._do_modeling()
-
- # Create variables
+ self._create_storage_variables()
+ self._add_netto_discharge_constraint()
+ self._add_energy_balance_constraint()
+ self._add_cluster_cyclic_constraint()
+ self._add_investment_model()
+ self._add_initial_final_constraints()
+ self._add_balanced_sizes_constraint()
+
+ def _create_storage_variables(self):
+ """Create charge_state and netto_discharge variables."""
lb, ub = self._absolute_charge_state_bounds
self.add_variables(
lower=lb,
@@ -887,35 +941,30 @@ def _do_modeling(self):
coords=self._model.get_coords(extra_timestep=True),
short_name='charge_state',
)
-
self.add_variables(coords=self._model.get_coords(), short_name='netto_discharge')
- # Create constraints (can now access flow.submodel.flow_rate)
- # netto_discharge:
- # eq: nettoFlow(t) - discharging(t) + charging(t) = 0
+ def _add_netto_discharge_constraint(self):
+ """Add constraint: netto_discharge = discharging - charging."""
self.add_constraints(
self.netto_discharge
== self.element.discharging.submodel.flow_rate - self.element.charging.submodel.flow_rate,
short_name='netto_discharge',
)
- charge_state = self.charge_state
- rel_loss = self.element.relative_loss_per_hour
- hours_per_step = self._model.hours_per_step
- charge_rate = self.element.charging.submodel.flow_rate
- discharge_rate = self.element.discharging.submodel.flow_rate
- eff_charge = self.element.eta_charge
- eff_discharge = self.element.eta_discharge
+ def _add_energy_balance_constraint(self):
+ """Add energy balance constraint linking charge states across timesteps."""
+ self.add_constraints(self._build_energy_balance_lhs() == 0, short_name='charge_state')
- self.add_constraints(
- charge_state.isel(time=slice(1, None))
- == charge_state.isel(time=slice(None, -1)) * ((1 - rel_loss) ** hours_per_step)
- + charge_rate * eff_charge * hours_per_step
- - discharge_rate * hours_per_step / eff_discharge,
- short_name='charge_state',
- )
+ def _add_cluster_cyclic_constraint(self):
+ """For 'cyclic' cluster mode: each cluster's start equals its end."""
+ if self._model.flow_system.clusters is not None and self.element.cluster_mode == 'cyclic':
+ self.add_constraints(
+ self.charge_state.isel(time=0) == self.charge_state.isel(time=-2),
+ short_name='cluster_cyclic',
+ )
- # Create InvestmentModel and bounding constraints for investment
+ def _add_investment_model(self):
+ """Create InvestmentModel and add capacity-scaled bounds if using investment sizing."""
if isinstance(self.element.capacity_in_flow_hours, InvestParameters):
self.add_submodels(
InvestmentModel(
@@ -926,7 +975,6 @@ def _do_modeling(self):
),
short_name='investment',
)
-
BoundingPatterns.scaled_bounds(
self,
variable=self.charge_state,
@@ -934,22 +982,28 @@ def _do_modeling(self):
relative_bounds=self._relative_charge_state_bounds,
)
- # Initial charge state
- self._initial_and_final_charge_state()
+ def _add_initial_final_constraints(self):
+ """Add initial and final charge state constraints.
- # Balanced sizes
- if self.element.balanced:
- self.add_constraints(
- self.element.charging.submodel._investment.size * 1
- == self.element.discharging.submodel._investment.size * 1,
- short_name='balanced_sizes',
- )
+ For clustered systems with 'independent' or 'cyclic' mode, these constraints
+ are skipped because:
+ - 'independent': Each cluster has free start/end SOC
+ - 'cyclic': Start == end is handled by _add_cluster_cyclic_constraint,
+ but no specific initial value is enforced
+ """
+ # Skip initial/final constraints for clustered systems with independent/cyclic mode
+ # These modes should have free or cyclic SOC, not a fixed initial value per cluster
+ if self._model.flow_system.clusters is not None and self.element.cluster_mode in (
+ 'independent',
+ 'cyclic',
+ ):
+ return
- def _initial_and_final_charge_state(self):
if self.element.initial_charge_state is not None:
if isinstance(self.element.initial_charge_state, str):
self.add_constraints(
- self.charge_state.isel(time=0) == self.charge_state.isel(time=-1), short_name='initial_charge_state'
+ self.charge_state.isel(time=0) == self.charge_state.isel(time=-1),
+ short_name='initial_charge_state',
)
else:
self.add_constraints(
@@ -969,21 +1023,73 @@ def _initial_and_final_charge_state(self):
short_name='final_charge_min',
)
+ def _add_balanced_sizes_constraint(self):
+ """Add constraint ensuring charging and discharging capacities are equal."""
+ if self.element.balanced:
+ self.add_constraints(
+ self.element.charging.submodel._investment.size * 1
+ == self.element.discharging.submodel._investment.size * 1,
+ short_name='balanced_sizes',
+ )
+
+ def _build_energy_balance_lhs(self):
+ """Build the left-hand side of the energy balance constraint.
+
+ The energy balance equation is:
+ charge_state[t+1] = charge_state[t] * (1 - loss)^dt
+ + charge_rate * eta_charge * dt
+ - discharge_rate / eta_discharge * dt
+
+ Rearranged as LHS = 0:
+ charge_state[t+1] - charge_state[t] * (1 - loss)^dt
+ - charge_rate * eta_charge * dt
+ + discharge_rate / eta_discharge * dt = 0
+
+ Returns:
+ The LHS expression (should equal 0).
+ """
+ charge_state = self.charge_state
+ rel_loss = self.element.relative_loss_per_hour
+ timestep_duration = self._model.timestep_duration
+ charge_rate = self.element.charging.submodel.flow_rate
+ discharge_rate = self.element.discharging.submodel.flow_rate
+ eff_charge = self.element.eta_charge
+ eff_discharge = self.element.eta_discharge
+
+ return (
+ charge_state.isel(time=slice(1, None))
+ - charge_state.isel(time=slice(None, -1)) * ((1 - rel_loss) ** timestep_duration)
+ - charge_rate * eff_charge * timestep_duration
+ + discharge_rate * timestep_duration / eff_discharge
+ )
+
@property
def _absolute_charge_state_bounds(self) -> tuple[xr.DataArray, xr.DataArray]:
+ """Get absolute bounds for charge_state variable.
+
+ For base StorageModel, charge_state represents absolute SOC with bounds
+ derived from relative bounds scaled by capacity.
+
+ Note:
+ InterclusterStorageModel overrides this to provide symmetric bounds
+ since charge_state represents ΞE (relative change from cluster start).
+ """
relative_lower_bound, relative_upper_bound = self._relative_charge_state_bounds
+
if self.element.capacity_in_flow_hours is None:
- # Unbounded storage: lower bound is 0, upper bound is infinite
- return (0, np.inf)
+ return 0, np.inf
elif isinstance(self.element.capacity_in_flow_hours, InvestParameters):
+ cap_min = self.element.capacity_in_flow_hours.minimum_or_fixed_size
+ cap_max = self.element.capacity_in_flow_hours.maximum_or_fixed_size
return (
- relative_lower_bound * self.element.capacity_in_flow_hours.minimum_or_fixed_size,
- relative_upper_bound * self.element.capacity_in_flow_hours.maximum_or_fixed_size,
+ relative_lower_bound * cap_min,
+ relative_upper_bound * cap_max,
)
else:
+ cap = self.element.capacity_in_flow_hours
return (
- relative_lower_bound * self.element.capacity_in_flow_hours,
- relative_upper_bound * self.element.capacity_in_flow_hours,
+ relative_lower_bound * cap,
+ relative_upper_bound * cap,
)
@property
@@ -1038,6 +1144,411 @@ def netto_discharge(self) -> linopy.Variable:
return self['netto_discharge']
+class InterclusterStorageModel(StorageModel):
+ """Storage model with inter-cluster linking for clustered optimization.
+
+ This class extends :class:`StorageModel` to support inter-cluster storage linking
+ when using time series aggregation (clustering). It implements the S-N linking model
+ from Blanke et al. (2022) to properly value seasonal storage in clustered optimizations.
+
+ The Problem with Naive Clustering
+ ---------------------------------
+ When time series are clustered (e.g., 365 days β 8 typical days), storage behavior
+ is fundamentally misrepresented if each cluster operates independently:
+
+ - **Seasonal patterns are lost**: A battery might charge in summer and discharge in
+ winter, but with independent clusters, each "typical summer day" cannot transfer
+ energy to the "typical winter day".
+ - **Storage value is underestimated**: Without inter-cluster linking, storage can only
+ provide intra-day flexibility, not seasonal arbitrage.
+
+ The S-N Linking Model
+ ---------------------
+ This model introduces two key concepts:
+
+ 1. **SOC_boundary**: Absolute state-of-charge at the boundary between original periods.
+ With N original periods, there are N+1 boundary points (including start and end).
+
+ 2. **charge_state (ΞE)**: Relative change in SOC within each representative cluster,
+ measured from the cluster start (where ΞE = 0).
+
+ The actual SOC at any timestep t within original period d is::
+
+ SOC(t) = SOC_boundary[d] + ΞE(t)
+
+ Key Constraints
+ ---------------
+ 1. **Cluster start constraint**: ``ΞE(cluster_start) = 0``
+ Each representative cluster starts with zero relative charge.
+
+ 2. **Linking constraint**: ``SOC_boundary[d+1] = SOC_boundary[d] + delta_SOC[cluster_order[d]]``
+ The boundary SOC after period d equals the boundary before plus the net
+ charge/discharge of the representative cluster for that period.
+
+ 3. **Combined bounds**: ``0 β€ SOC_boundary[d] + ΞE(t) β€ capacity``
+ The actual SOC must stay within physical bounds.
+
+ 4. **Cyclic constraint** (for ``intercluster_cyclic`` mode):
+ ``SOC_boundary[0] = SOC_boundary[N]``
+ The storage returns to its initial state over the full time horizon.
+
+ Variables Created
+ -----------------
+ - ``SOC_boundary``: Absolute SOC at each original period boundary.
+ Shape: (n_original_clusters + 1,) plus any period/scenario dimensions.
+
+ Constraints Created
+ -------------------
+ - ``cluster_start``: Forces ΞE = 0 at start of each representative cluster.
+ - ``link``: Links consecutive SOC_boundary values via delta_SOC.
+ - ``cyclic`` or ``initial_SOC_boundary``: Initial/final boundary condition.
+ - ``soc_lb_start/mid/end``: Lower bound on combined SOC at sample points.
+ - ``soc_ub_start/mid/end``: Upper bound on combined SOC (if investment).
+ - ``SOC_boundary_ub``: Links SOC_boundary to investment size (if investment).
+ - ``charge_state|lb/ub``: Symmetric bounds on ΞE for intercluster modes.
+
+ References
+ ----------
+ - Blanke, T., et al. (2022). "Inter-Cluster Storage Linking for Time Series
+ Aggregation in Energy System Optimization Models."
+ - Kotzur, L., et al. (2018). "Time series aggregation for energy system design:
+ Modeling seasonal storage."
+
+ See Also
+ --------
+ :class:`StorageModel` : Base storage model without inter-cluster linking.
+ :class:`Storage` : The element class that creates this model.
+
+ Example
+ -------
+ The model is automatically used when a Storage has ``cluster_mode='intercluster'``
+ or ``cluster_mode='intercluster_cyclic'`` and the FlowSystem has been clustered::
+
+ storage = Storage(
+ label='seasonal_storage',
+ charging=charge_flow,
+ discharging=discharge_flow,
+ capacity_in_flow_hours=InvestParameters(maximum_size=10000),
+ cluster_mode='intercluster_cyclic', # Enable inter-cluster linking
+ )
+
+ # Cluster the flow system
+ fs_clustered = flow_system.transform.cluster(n_clusters=8)
+ fs_clustered.optimize(solver)
+
+ # Access the SOC_boundary in results
+ soc_boundary = fs_clustered.solution['seasonal_storage|SOC_boundary']
+ """
+
+ @property
+ def _absolute_charge_state_bounds(self) -> tuple[xr.DataArray, xr.DataArray]:
+ """Get symmetric bounds for charge_state (ΞE) variable.
+
+ For InterclusterStorageModel, charge_state represents ΞE (relative change
+ from cluster start), which can be negative. Therefore, we need symmetric
+ bounds: -capacity <= ΞE <= capacity.
+
+ Note that for investment-based sizing, additional constraints are added
+ in _add_investment_model to link bounds to the actual investment size.
+ """
+ _, relative_upper_bound = self._relative_charge_state_bounds
+
+ if self.element.capacity_in_flow_hours is None:
+ return -np.inf, np.inf
+ elif isinstance(self.element.capacity_in_flow_hours, InvestParameters):
+ cap_max = self.element.capacity_in_flow_hours.maximum_or_fixed_size * relative_upper_bound
+ # Adding 0.0 converts -0.0 to 0.0 (linopy LP writer bug workaround)
+ return -cap_max + 0.0, cap_max + 0.0
+ else:
+ cap = self.element.capacity_in_flow_hours * relative_upper_bound
+ # Adding 0.0 converts -0.0 to 0.0 (linopy LP writer bug workaround)
+ return -cap + 0.0, cap + 0.0
+
+ def _do_modeling(self):
+ """Create storage model with inter-cluster linking constraints.
+
+ Uses template method pattern: calls parent's _do_modeling, then adds
+ inter-cluster linking. Overrides specific methods to customize behavior.
+ """
+ super()._do_modeling()
+ self._add_intercluster_linking()
+
+ def _add_cluster_cyclic_constraint(self):
+ """Skip cluster cyclic constraint - handled by inter-cluster linking."""
+ pass
+
+ def _add_investment_model(self):
+ """Create InvestmentModel with symmetric bounds for ΞE."""
+ if isinstance(self.element.capacity_in_flow_hours, InvestParameters):
+ self.add_submodels(
+ InvestmentModel(
+ model=self._model,
+ label_of_element=self.label_of_element,
+ label_of_model=self.label_of_element,
+ parameters=self.element.capacity_in_flow_hours,
+ ),
+ short_name='investment',
+ )
+ # Symmetric bounds: -size <= charge_state <= size
+ self.add_constraints(
+ self.charge_state >= -self.investment.size,
+ short_name='charge_state|lb',
+ )
+ self.add_constraints(
+ self.charge_state <= self.investment.size,
+ short_name='charge_state|ub',
+ )
+
+ def _add_initial_final_constraints(self):
+ """Skip initial/final constraints - handled by SOC_boundary in inter-cluster linking."""
+ pass
+
+ def _add_intercluster_linking(self) -> None:
+ """Add inter-cluster storage linking following the S-K model from Blanke et al. (2022).
+
+ This method implements the core inter-cluster linking logic:
+
+ 1. Constrains charge_state (ΞE) at each cluster start to 0
+ 2. Creates SOC_boundary variables to track absolute SOC at period boundaries
+ 3. Links boundaries via Eq. 5: SOC_boundary[d+1] = SOC_boundary[d] * (1-loss)^N + delta_SOC
+ 4. Adds combined bounds per Eq. 9: 0 β€ SOC_boundary * (1-loss)^t + ΞE β€ capacity
+ 5. Enforces initial/cyclic constraint on SOC_boundary
+ """
+ from .clustering.intercluster_helpers import (
+ build_boundary_coords,
+ extract_capacity_bounds,
+ )
+
+ clustering = self._model.flow_system.clustering
+ if clustering is None or clustering.result.cluster_structure is None:
+ return
+
+ cluster_structure = clustering.result.cluster_structure
+ n_clusters = (
+ int(cluster_structure.n_clusters)
+ if isinstance(cluster_structure.n_clusters, (int, np.integer))
+ else int(cluster_structure.n_clusters.values)
+ )
+ timesteps_per_cluster = cluster_structure.timesteps_per_cluster
+ n_original_clusters = cluster_structure.n_original_clusters
+ cluster_order = cluster_structure.cluster_order
+
+ # 1. Constrain ΞE = 0 at cluster starts
+ self._add_cluster_start_constraints(n_clusters, timesteps_per_cluster)
+
+ # 2. Create SOC_boundary variable
+ flow_system = self._model.flow_system
+ boundary_coords, boundary_dims = build_boundary_coords(n_original_clusters, flow_system)
+ capacity_bounds = extract_capacity_bounds(self.element.capacity_in_flow_hours, boundary_coords, boundary_dims)
+
+ soc_boundary = self.add_variables(
+ lower=capacity_bounds.lower,
+ upper=capacity_bounds.upper,
+ coords=boundary_coords,
+ dims=boundary_dims,
+ short_name='SOC_boundary',
+ )
+
+ # 3. Link SOC_boundary to investment size
+ if capacity_bounds.has_investment and self.investment is not None:
+ self.add_constraints(
+ soc_boundary <= self.investment.size,
+ short_name='SOC_boundary_ub',
+ )
+
+ # 4. Compute delta_SOC for each cluster
+ delta_soc = self._compute_delta_soc(n_clusters, timesteps_per_cluster)
+
+ # 5. Add linking constraints
+ self._add_linking_constraints(
+ soc_boundary, delta_soc, cluster_order, n_original_clusters, timesteps_per_cluster
+ )
+
+ # 6. Add cyclic or initial constraint
+ if self.element.cluster_mode == 'intercluster_cyclic':
+ self.add_constraints(
+ soc_boundary.isel(cluster_boundary=0) == soc_boundary.isel(cluster_boundary=n_original_clusters),
+ short_name='cyclic',
+ )
+ else:
+ # Apply initial_charge_state to SOC_boundary[0]
+ initial = self.element.initial_charge_state
+ if initial is not None:
+ if isinstance(initial, str):
+ # 'equals_final' means cyclic
+ self.add_constraints(
+ soc_boundary.isel(cluster_boundary=0)
+ == soc_boundary.isel(cluster_boundary=n_original_clusters),
+ short_name='initial_SOC_boundary',
+ )
+ else:
+ self.add_constraints(
+ soc_boundary.isel(cluster_boundary=0) == initial,
+ short_name='initial_SOC_boundary',
+ )
+
+ # 7. Add combined bound constraints
+ self._add_combined_bound_constraints(
+ soc_boundary,
+ cluster_order,
+ capacity_bounds.has_investment,
+ n_original_clusters,
+ timesteps_per_cluster,
+ )
+
+ def _add_cluster_start_constraints(self, n_clusters: int, timesteps_per_cluster: int) -> None:
+ """Constrain ΞE = 0 at the start of each representative cluster.
+
+ This ensures that the relative charge state is measured from a known
+ reference point (the cluster start).
+
+ With 2D (cluster, time) structure, time=0 is the start of every cluster,
+ so we simply select isel(time=0) which broadcasts across the cluster dimension.
+
+ Args:
+ n_clusters: Number of representative clusters (unused with 2D structure).
+ timesteps_per_cluster: Timesteps in each cluster (unused with 2D structure).
+ """
+ # With 2D structure: time=0 is start of every cluster
+ self.add_constraints(
+ self.charge_state.isel(time=0) == 0,
+ short_name='cluster_start',
+ )
+
+ def _compute_delta_soc(self, n_clusters: int, timesteps_per_cluster: int) -> xr.DataArray:
+ """Compute net SOC change (delta_SOC) for each representative cluster.
+
+ The delta_SOC is the difference between the charge_state at the end
+ and start of each cluster: delta_SOC[c] = ΞE(end_c) - ΞE(start_c).
+
+ Since ΞE(start) = 0 by constraint, this simplifies to delta_SOC[c] = ΞE(end_c).
+
+ With 2D (cluster, time) structure, we can simply select isel(time=-1) and isel(time=0),
+ which already have the 'cluster' dimension.
+
+ Args:
+ n_clusters: Number of representative clusters (unused with 2D structure).
+ timesteps_per_cluster: Timesteps in each cluster (unused with 2D structure).
+
+ Returns:
+ DataArray with 'cluster' dimension containing delta_SOC for each cluster.
+ """
+ # With 2D structure: result already has cluster dimension
+ return self.charge_state.isel(time=-1) - self.charge_state.isel(time=0)
+
+ def _add_linking_constraints(
+ self,
+ soc_boundary: xr.DataArray,
+ delta_soc: xr.DataArray,
+ cluster_order: xr.DataArray,
+ n_original_clusters: int,
+ timesteps_per_cluster: int,
+ ) -> None:
+ """Add constraints linking consecutive SOC_boundary values.
+
+ Per Blanke et al. (2022) Eq. 5, implements:
+ SOC_boundary[d+1] = SOC_boundary[d] * (1-loss)^N + delta_SOC[cluster_order[d]]
+
+ where N is timesteps_per_cluster and loss is self-discharge rate per timestep.
+
+ This connects the SOC at the end of original period d to the SOC at the
+ start of period d+1, accounting for self-discharge decay over the period.
+
+ Args:
+ soc_boundary: SOC_boundary variable.
+ delta_soc: Net SOC change per cluster.
+ cluster_order: Mapping from original periods to representative clusters.
+ n_original_clusters: Number of original (non-clustered) periods.
+ timesteps_per_cluster: Number of timesteps in each cluster period.
+ """
+ soc_after = soc_boundary.isel(cluster_boundary=slice(1, None))
+ soc_before = soc_boundary.isel(cluster_boundary=slice(None, -1))
+
+ # Rename for alignment
+ soc_after = soc_after.rename({'cluster_boundary': 'original_cluster'})
+ soc_after = soc_after.assign_coords(original_cluster=np.arange(n_original_clusters))
+ soc_before = soc_before.rename({'cluster_boundary': 'original_cluster'})
+ soc_before = soc_before.assign_coords(original_cluster=np.arange(n_original_clusters))
+
+ # Get delta_soc for each original period using cluster_order
+ delta_soc_ordered = delta_soc.isel(cluster=cluster_order)
+
+ # Apply self-discharge decay factor (1-loss)^N to soc_before per Eq. 5
+ # Use mean over time (linking operates at period level, not timestep)
+ # Keep as DataArray to respect per-period/scenario values
+ rel_loss = self.element.relative_loss_per_hour.mean('time')
+ decay_n = (1 - rel_loss) ** timesteps_per_cluster
+
+ lhs = soc_after - soc_before * decay_n - delta_soc_ordered
+ self.add_constraints(lhs == 0, short_name='link')
+
+ def _add_combined_bound_constraints(
+ self,
+ soc_boundary: xr.DataArray,
+ cluster_order: xr.DataArray,
+ has_investment: bool,
+ n_original_clusters: int,
+ timesteps_per_cluster: int,
+ ) -> None:
+ """Add constraints ensuring actual SOC stays within bounds.
+
+ Per Blanke et al. (2022) Eq. 9, the actual SOC at time t in period d is:
+ SOC(t) = SOC_boundary[d] * (1-loss)^t + ΞE(t)
+
+ This must satisfy: 0 β€ SOC(t) β€ capacity
+
+ Since checking every timestep is expensive, we sample at the start,
+ middle, and end of each cluster.
+
+ With 2D (cluster, time) structure, we simply select charge_state at a
+ given time offset, then reorder by cluster_order to get original_cluster order.
+
+ Args:
+ soc_boundary: SOC_boundary variable.
+ cluster_order: Mapping from original periods to clusters.
+ has_investment: Whether the storage has investment sizing.
+ n_original_clusters: Number of original periods.
+ timesteps_per_cluster: Timesteps in each cluster.
+ """
+ charge_state = self.charge_state
+
+ # soc_d: SOC at start of each original period
+ soc_d = soc_boundary.isel(cluster_boundary=slice(None, -1))
+ soc_d = soc_d.rename({'cluster_boundary': 'original_cluster'})
+ soc_d = soc_d.assign_coords(original_cluster=np.arange(n_original_clusters))
+
+ # Get self-discharge rate for decay calculation
+ # Keep as DataArray to respect per-period/scenario values
+ rel_loss = self.element.relative_loss_per_hour.mean('time')
+
+ sample_offsets = [0, timesteps_per_cluster // 2, timesteps_per_cluster - 1]
+
+ for sample_name, offset in zip(['start', 'mid', 'end'], sample_offsets, strict=False):
+ # With 2D structure: select time offset, then reorder by cluster_order
+ cs_at_offset = charge_state.isel(time=offset) # Shape: (cluster, ...)
+ # Reorder to original_cluster order using cluster_order indexer
+ cs_t = cs_at_offset.isel(cluster=cluster_order)
+ # Suppress xarray warning about index loss - we immediately assign new coords anyway
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', message='.*does not create an index anymore.*')
+ cs_t = cs_t.rename({'cluster': 'original_cluster'})
+ cs_t = cs_t.assign_coords(original_cluster=np.arange(n_original_clusters))
+
+ # Apply decay factor (1-loss)^t to SOC_boundary per Eq. 9
+ decay_t = (1 - rel_loss) ** offset
+ combined = soc_d * decay_t + cs_t
+
+ self.add_constraints(combined >= 0, short_name=f'soc_lb_{sample_name}')
+
+ if has_investment and self.investment is not None:
+ self.add_constraints(combined <= self.investment.size, short_name=f'soc_ub_{sample_name}')
+ elif not has_investment and isinstance(self.element.capacity_in_flow_hours, (int, float)):
+ # Fixed-capacity storage: upper bound is the fixed capacity
+ self.add_constraints(
+ combined <= self.element.capacity_in_flow_hours, short_name=f'soc_ub_{sample_name}'
+ )
+
+
@register_class_for_io
class SourceAndSink(Component):
"""
diff --git a/flixopt/config.py b/flixopt/config.py
index a29027d65..3bc3d5ebf 100644
--- a/flixopt/config.py
+++ b/flixopt/config.py
@@ -30,7 +30,7 @@
logging.addLevelName(SUCCESS_LEVEL, 'SUCCESS')
# Deprecation removal version - update this when planning the next major version
-DEPRECATION_REMOVAL_VERSION = '6.0.0'
+DEPRECATION_REMOVAL_VERSION = '7.0.0'
class MultilineFormatter(logging.Formatter):
@@ -163,6 +163,9 @@ def format(self, record):
'default_facet_cols': 3,
'default_sequential_colorscale': 'turbo',
'default_qualitative_colorscale': 'plotly',
+ 'default_line_shape': 'hv',
+ 'dim_priority': ('time', 'duration', 'duration_pct', 'variable', 'cluster', 'period', 'scenario'),
+ 'slot_priority': ('x', 'color', 'facet_col', 'facet_row', 'animation_frame'),
}
),
'solving': MappingProxyType(
@@ -558,6 +561,10 @@ class Plotting:
default_facet_cols: Default number of columns for faceted plots.
default_sequential_colorscale: Default colorscale for heatmaps and continuous data.
default_qualitative_colorscale: Default colormap for categorical plots (bar/line/area charts).
+ dim_priority: Priority order for assigning dimensions to plot slots.
+ Dimensions are assigned to slots based on this order.
+ slot_priority: Order in which slots are filled during auto-assignment.
+ Default: x β color β facet_col β facet_row β animation_frame.
Examples:
```python
@@ -565,6 +572,12 @@ class Plotting:
CONFIG.Plotting.default_dpi = 600
CONFIG.Plotting.default_sequential_colorscale = 'plasma'
CONFIG.Plotting.default_qualitative_colorscale = 'Dark24'
+
+ # Customize dimension priority for auto-assignment
+ CONFIG.Plotting.dim_priority = ('time', 'scenario', 'variable', 'period', 'cluster')
+
+ # Change slot fill order (e.g., prioritize facets over color)
+ CONFIG.Plotting.slot_priority = ('x', 'facet_col', 'facet_row', 'color', 'animation_frame')
```
"""
@@ -574,6 +587,9 @@ class Plotting:
default_facet_cols: int = _DEFAULTS['plotting']['default_facet_cols']
default_sequential_colorscale: str = _DEFAULTS['plotting']['default_sequential_colorscale']
default_qualitative_colorscale: str = _DEFAULTS['plotting']['default_qualitative_colorscale']
+ default_line_shape: str = _DEFAULTS['plotting']['default_line_shape']
+ dim_priority: tuple[str, ...] = _DEFAULTS['plotting']['dim_priority']
+ slot_priority: tuple[str, ...] = _DEFAULTS['plotting']['slot_priority']
class Carriers:
"""Default carrier definitions for common energy types.
@@ -674,6 +690,9 @@ def to_dict(cls) -> dict:
'default_facet_cols': cls.Plotting.default_facet_cols,
'default_sequential_colorscale': cls.Plotting.default_sequential_colorscale,
'default_qualitative_colorscale': cls.Plotting.default_qualitative_colorscale,
+ 'default_line_shape': cls.Plotting.default_line_shape,
+ 'dim_priority': cls.Plotting.dim_priority,
+ 'slot_priority': cls.Plotting.slot_priority,
},
}
diff --git a/flixopt/core.py b/flixopt/core.py
index a14aa6654..3d456fff1 100644
--- a/flixopt/core.py
+++ b/flixopt/core.py
@@ -15,7 +15,7 @@
logger = logging.getLogger('flixopt')
-FlowSystemDimensions = Literal['time', 'period', 'scenario']
+FlowSystemDimensions = Literal['time', 'cluster', 'period', 'scenario']
"""Possible dimensions of a FlowSystem."""
@@ -522,7 +522,9 @@ def _validate_and_prepare_target_coordinates(
coord_index = coord_index.rename(dim_name)
# Special validation for time dimensions (common pattern)
- if dim_name == 'time' and not isinstance(coord_index, pd.DatetimeIndex):
+ # Allow integer indices when 'cluster' dimension is present (clustered mode)
+ has_cluster_dim = 'cluster' in coords
+ if dim_name == 'time' and not isinstance(coord_index, pd.DatetimeIndex) and not has_cluster_dim:
raise ConversionError(
f'Dimension named "time" should use DatetimeIndex for proper '
f'time-series functionality, got {type(coord_index).__name__}'
diff --git a/flixopt/dataset_plot_accessor.py b/flixopt/dataset_plot_accessor.py
new file mode 100644
index 000000000..6c833e652
--- /dev/null
+++ b/flixopt/dataset_plot_accessor.py
@@ -0,0 +1,997 @@
+"""Xarray accessors for plotting (``.fxplot``) and statistics (``.fxstats``)."""
+
+from __future__ import annotations
+
+import warnings
+from typing import Any, Literal
+
+import pandas as pd
+import plotly.express as px
+import plotly.graph_objects as go
+import xarray as xr
+
+from .color_processing import ColorType, process_colors
+from .config import CONFIG
+
+
+def assign_slots(
+ ds: xr.Dataset,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ color: str | Literal['auto'] | None = 'auto',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ exclude_dims: set[str] | None = None,
+) -> dict[str, str | None]:
+ """Assign dimensions to plot slots using CONFIG.Plotting.dim_priority.
+
+ Dimensions are assigned in priority order to slots based on CONFIG.Plotting.slot_priority.
+
+ Slot values:
+ - 'auto': auto-assign from available dims using priority
+ - None: skip this slot (not available for this plot type)
+ - str: use this specific dimension
+
+ 'variable' is treated as a dimension when len(data_vars) > 1. It represents
+ the data_var names column in the melted DataFrame.
+
+ Args:
+ ds: Dataset to analyze for available dimensions.
+ x: X-axis dimension. 'auto' assigns first available from priority.
+ color: Color grouping dimension.
+ facet_col: Column faceting dimension.
+ facet_row: Row faceting dimension.
+ animation_frame: Animation slider dimension.
+ exclude_dims: Dimensions to exclude from auto-assignment (e.g., already used for x elsewhere).
+
+ Returns:
+ Dict with keys 'x', 'color', 'facet_col', 'facet_row', 'animation_frame'
+ and values being assigned dimension names (or None if slot skipped/unfilled).
+ """
+ # Get available dimensions with size > 1, excluding specified dims
+ exclude = exclude_dims or set()
+ available = {d for d in ds.dims if ds.sizes[d] > 1 and d not in exclude}
+ # 'variable' is available when there are multiple data_vars (and not excluded)
+ if len(ds.data_vars) > 1 and 'variable' not in exclude:
+ available.add('variable')
+
+ # Get priority-ordered list of available dims
+ priority_dims = [d for d in CONFIG.Plotting.dim_priority if d in available]
+ # Add any available dims not in priority list (fallback)
+ priority_dims.extend(d for d in available if d not in priority_dims)
+
+ # Slot specification
+ slots = {
+ 'x': x,
+ 'color': color,
+ 'facet_col': facet_col,
+ 'facet_row': facet_row,
+ 'animation_frame': animation_frame,
+ }
+ # Slot fill order from config
+ slot_order = CONFIG.Plotting.slot_priority
+
+ results: dict[str, str | None] = {k: None for k in slot_order}
+ used: set[str] = set()
+
+ # First pass: resolve explicit dimensions (not 'auto' or None) to mark them as used
+ for slot_name, value in slots.items():
+ if value is not None and value != 'auto':
+ used.add(value)
+ results[slot_name] = value
+
+ # Second pass: resolve 'auto' slots in config-defined fill order
+ dim_iter = iter(d for d in priority_dims if d not in used)
+ for slot_name in slot_order:
+ if slots[slot_name] == 'auto':
+ next_dim = next(dim_iter, None)
+ if next_dim:
+ used.add(next_dim)
+ results[slot_name] = next_dim
+
+ # Warn if any dimensions were not assigned to any slot
+ unassigned = available - used
+ if unassigned:
+ available_slots = [k for k, v in slots.items() if v is not None]
+ unavailable_slots = [k for k, v in slots.items() if v is None]
+ if unavailable_slots:
+ warnings.warn(
+ f'Dimensions {unassigned} not assigned to any plot dimension. '
+ f'Not available for this plot type: {unavailable_slots}. '
+ f'Reduce dimensions before plotting (e.g., .sel(), .isel(), .mean()).',
+ stacklevel=3,
+ )
+ else:
+ warnings.warn(
+ f'Dimensions {unassigned} not assigned to any plot dimension ({available_slots}). '
+ f'Reduce dimensions before plotting (e.g., .sel(), .isel(), .mean()).',
+ stacklevel=3,
+ )
+
+ return results
+
+
+def _build_fig_kwargs(
+ slots: dict[str, str | None],
+ ds_sizes: dict[str, int],
+ px_kwargs: dict[str, Any],
+ facet_cols: int | None = None,
+) -> dict[str, Any]:
+ """Build plotly express kwargs from slot assignments.
+
+ Adds facet/animation args only if slots are assigned and not overridden in px_kwargs.
+ Handles facet_col_wrap based on dimension size.
+ """
+ facet_col_wrap = facet_cols or CONFIG.Plotting.default_facet_cols
+ result: dict[str, Any] = {}
+
+ # Add facet/animation kwargs from slots (skip if None or already in px_kwargs)
+ for slot in ('color', 'facet_col', 'facet_row', 'animation_frame'):
+ if slots.get(slot) and slot not in px_kwargs:
+ result[slot] = slots[slot]
+
+ # Add facet_col_wrap if facet_col is set and dimension is large enough
+ if result.get('facet_col'):
+ dim_size = ds_sizes.get(result['facet_col'], facet_col_wrap + 1)
+ if facet_col_wrap < dim_size:
+ result['facet_col_wrap'] = facet_col_wrap
+
+ return result
+
+
+def _dataset_to_long_df(ds: xr.Dataset, value_name: str = 'value', var_name: str = 'variable') -> pd.DataFrame:
+ """Convert Dataset to long-form DataFrame for Plotly Express."""
+ if not ds.data_vars:
+ return pd.DataFrame()
+ if all(ds[var].ndim == 0 for var in ds.data_vars):
+ rows = [{var_name: var, value_name: float(ds[var].values)} for var in ds.data_vars]
+ return pd.DataFrame(rows)
+ df = ds.to_dataframe().reset_index()
+ # Use dims (not just coords) as id_vars - dims without coords become integer indices
+ id_cols = [c for c in ds.dims if c in df.columns]
+ return df.melt(id_vars=id_cols, var_name=var_name, value_name=value_name)
+
+
+@xr.register_dataset_accessor('fxplot')
+class DatasetPlotAccessor:
+ """Plot accessor for any xr.Dataset. Access via ``dataset.fxplot``.
+
+ Provides convenient plotting methods that automatically handle multi-dimensional
+ data through faceting and animation. All methods return a Plotly Figure.
+
+ This accessor is globally registered when flixopt is imported and works on
+ any xr.Dataset.
+
+ Examples:
+ Basic usage::
+
+ import flixopt
+ import xarray as xr
+
+ ds = xr.Dataset({'A': (['time'], [1, 2, 3]), 'B': (['time'], [3, 2, 1])})
+ ds.fxplot.stacked_bar()
+ ds.fxplot.line()
+ ds.fxplot.area()
+
+ With faceting::
+
+ ds.fxplot.stacked_bar(facet_col='scenario')
+ ds.fxplot.line(facet_col='period', animation_frame='scenario')
+
+ Heatmap::
+
+ ds.fxplot.heatmap('temperature')
+ """
+
+ def __init__(self, xarray_obj: xr.Dataset) -> None:
+ """Initialize the accessor with an xr.Dataset object."""
+ self._ds = xarray_obj
+
+ def bar(
+ self,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ color: str | Literal['auto'] | None = 'auto',
+ colors: ColorType | None = None,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ exclude_dims: set[str] | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a grouped bar chart from the dataset.
+
+ Args:
+ x: Dimension for x-axis. 'auto' uses CONFIG.Plotting.dim_priority.
+ color: Dimension for color grouping. 'auto' uses 'variable' (data_var names)
+ if available, otherwise uses CONFIG priority.
+ colors: Color specification (colorscale name, color list, or dict mapping).
+ title: Plot title.
+ xlabel: X-axis label.
+ ylabel: Y-axis label.
+ facet_col: Dimension for column facets. 'auto' uses CONFIG priority.
+ facet_row: Dimension for row facets. 'auto' uses CONFIG priority.
+ animation_frame: Dimension for animation slider.
+ facet_cols: Number of columns in facet grid wrap.
+ exclude_dims: Dimensions to exclude from auto-assignment.
+ **px_kwargs: Additional arguments passed to plotly.express.bar.
+
+ Returns:
+ Plotly Figure.
+ """
+ slots = assign_slots(
+ self._ds,
+ x=x,
+ color=color,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ exclude_dims=exclude_dims,
+ )
+ df = _dataset_to_long_df(self._ds)
+ if df.empty:
+ return go.Figure()
+
+ color_labels = df[slots['color']].unique().tolist() if slots['color'] and slots['color'] in df.columns else []
+ color_map = process_colors(colors, color_labels, CONFIG.Plotting.default_qualitative_colorscale)
+
+ labels = {**(({slots['x']: xlabel}) if xlabel and slots['x'] else {}), **({'value': ylabel} if ylabel else {})}
+ fig_kwargs = {
+ 'data_frame': df,
+ 'x': slots['x'],
+ 'y': 'value',
+ 'title': title,
+ 'barmode': 'group',
+ 'color_discrete_map': color_map,
+ **({'labels': labels} if labels else {}),
+ **_build_fig_kwargs(slots, dict(self._ds.sizes), px_kwargs, facet_cols),
+ }
+ return px.bar(**{**fig_kwargs, **px_kwargs})
+
+ def stacked_bar(
+ self,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ color: str | Literal['auto'] | None = 'auto',
+ colors: ColorType | None = None,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ exclude_dims: set[str] | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a stacked bar chart from the dataset.
+
+ Variables in the dataset become stacked segments. Positive and negative
+ values are stacked separately.
+
+ Args:
+ x: Dimension for x-axis. 'auto' uses CONFIG.Plotting.dim_priority.
+ color: Dimension for color grouping. 'auto' uses 'variable' (data_var names)
+ if available, otherwise uses CONFIG priority.
+ colors: Color specification (colorscale name, color list, or dict mapping).
+ title: Plot title.
+ xlabel: X-axis label.
+ ylabel: Y-axis label.
+ facet_col: Dimension for column facets. 'auto' uses CONFIG priority.
+ facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
+ facet_cols: Number of columns in facet grid wrap.
+ **px_kwargs: Additional arguments passed to plotly.express.bar.
+
+ Returns:
+ Plotly Figure.
+ """
+ slots = assign_slots(
+ self._ds,
+ x=x,
+ color=color,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ exclude_dims=exclude_dims,
+ )
+ df = _dataset_to_long_df(self._ds)
+ if df.empty:
+ return go.Figure()
+
+ color_labels = df[slots['color']].unique().tolist() if slots['color'] and slots['color'] in df.columns else []
+ color_map = process_colors(colors, color_labels, CONFIG.Plotting.default_qualitative_colorscale)
+
+ labels = {**(({slots['x']: xlabel}) if xlabel and slots['x'] else {}), **({'value': ylabel} if ylabel else {})}
+ fig_kwargs = {
+ 'data_frame': df,
+ 'x': slots['x'],
+ 'y': 'value',
+ 'title': title,
+ 'color_discrete_map': color_map,
+ **({'labels': labels} if labels else {}),
+ **_build_fig_kwargs(slots, dict(self._ds.sizes), px_kwargs, facet_cols),
+ }
+ fig = px.bar(**{**fig_kwargs, **px_kwargs})
+ fig.update_layout(barmode='relative', bargap=0, bargroupgap=0)
+ fig.update_traces(marker_line_width=0)
+ return fig
+
+ def line(
+ self,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ color: str | Literal['auto'] | None = 'auto',
+ colors: ColorType | None = None,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ line_shape: str | None = None,
+ exclude_dims: set[str] | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a line chart from the dataset.
+
+ Each variable in the dataset becomes a separate line.
+
+ Args:
+ x: Dimension for x-axis. 'auto' uses CONFIG.Plotting.dim_priority.
+ color: Dimension for color grouping. 'auto' uses 'variable' (data_var names)
+ if available, otherwise uses CONFIG priority.
+ colors: Color specification (colorscale name, color list, or dict mapping).
+ title: Plot title.
+ xlabel: X-axis label.
+ ylabel: Y-axis label.
+ facet_col: Dimension for column facets. 'auto' uses CONFIG priority.
+ facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
+ facet_cols: Number of columns in facet grid wrap.
+ line_shape: Line interpolation ('linear', 'hv', 'vh', 'hvh', 'vhv', 'spline').
+ Default from CONFIG.Plotting.default_line_shape.
+ **px_kwargs: Additional arguments passed to plotly.express.line.
+
+ Returns:
+ Plotly Figure.
+ """
+ slots = assign_slots(
+ self._ds,
+ x=x,
+ color=color,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ exclude_dims=exclude_dims,
+ )
+ df = _dataset_to_long_df(self._ds)
+ if df.empty:
+ return go.Figure()
+
+ color_labels = df[slots['color']].unique().tolist() if slots['color'] and slots['color'] in df.columns else []
+ color_map = process_colors(colors, color_labels, CONFIG.Plotting.default_qualitative_colorscale)
+
+ labels = {**(({slots['x']: xlabel}) if xlabel and slots['x'] else {}), **({'value': ylabel} if ylabel else {})}
+ fig_kwargs = {
+ 'data_frame': df,
+ 'x': slots['x'],
+ 'y': 'value',
+ 'title': title,
+ 'line_shape': line_shape or CONFIG.Plotting.default_line_shape,
+ 'color_discrete_map': color_map,
+ **({'labels': labels} if labels else {}),
+ **_build_fig_kwargs(slots, dict(self._ds.sizes), px_kwargs, facet_cols),
+ }
+ return px.line(**{**fig_kwargs, **px_kwargs})
+
+ def area(
+ self,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ color: str | Literal['auto'] | None = 'auto',
+ colors: ColorType | None = None,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ line_shape: str | None = None,
+ exclude_dims: set[str] | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a stacked area chart from the dataset.
+
+ Args:
+ x: Dimension for x-axis. 'auto' uses CONFIG.Plotting.dim_priority.
+ color: Dimension for color grouping. 'auto' uses 'variable' (data_var names)
+ if available, otherwise uses CONFIG priority.
+ colors: Color specification (colorscale name, color list, or dict mapping).
+ title: Plot title.
+ xlabel: X-axis label.
+ ylabel: Y-axis label.
+ facet_col: Dimension for column facets. 'auto' uses CONFIG priority.
+ facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
+ facet_cols: Number of columns in facet grid wrap.
+ line_shape: Line interpolation. Default from CONFIG.Plotting.default_line_shape.
+ **px_kwargs: Additional arguments passed to plotly.express.area.
+
+ Returns:
+ Plotly Figure.
+ """
+ slots = assign_slots(
+ self._ds,
+ x=x,
+ color=color,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ exclude_dims=exclude_dims,
+ )
+ df = _dataset_to_long_df(self._ds)
+ if df.empty:
+ return go.Figure()
+
+ color_labels = df[slots['color']].unique().tolist() if slots['color'] and slots['color'] in df.columns else []
+ color_map = process_colors(colors, color_labels, CONFIG.Plotting.default_qualitative_colorscale)
+
+ labels = {**(({slots['x']: xlabel}) if xlabel and slots['x'] else {}), **({'value': ylabel} if ylabel else {})}
+ fig_kwargs = {
+ 'data_frame': df,
+ 'x': slots['x'],
+ 'y': 'value',
+ 'title': title,
+ 'line_shape': line_shape or CONFIG.Plotting.default_line_shape,
+ 'color_discrete_map': color_map,
+ **({'labels': labels} if labels else {}),
+ **_build_fig_kwargs(slots, dict(self._ds.sizes), px_kwargs, facet_cols),
+ }
+ return px.area(**{**fig_kwargs, **px_kwargs})
+
+ def heatmap(
+ self,
+ variable: str | None = None,
+ *,
+ colors: str | list[str] | None = None,
+ title: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ **imshow_kwargs: Any,
+ ) -> go.Figure:
+ """Create a heatmap visualization.
+
+ If the dataset has multiple variables, select one with the `variable` parameter.
+ If only one variable exists, it is used automatically.
+
+ Args:
+ variable: Variable name to plot. Required if dataset has multiple variables.
+ If None and dataset has one variable, that variable is used.
+ colors: Colorscale name or list of colors.
+ title: Plot title.
+ facet_col: Dimension for column facets.
+ animation_frame: Dimension for animation slider.
+ facet_cols: Number of columns in facet grid wrap.
+ **imshow_kwargs: Additional arguments passed to plotly.express.imshow.
+
+ Returns:
+ Plotly Figure.
+ """
+ # Select single variable
+ if variable is None:
+ if len(self._ds.data_vars) == 1:
+ variable = list(self._ds.data_vars)[0]
+ else:
+ raise ValueError(
+ f'Dataset has {len(self._ds.data_vars)} variables. '
+ f"Please specify which variable to plot with variable='name'."
+ )
+
+ da = self._ds[variable]
+
+ if da.size == 0:
+ return go.Figure()
+
+ colors = colors or CONFIG.Plotting.default_sequential_colorscale
+ facet_col_wrap = facet_cols or CONFIG.Plotting.default_facet_cols
+
+ # Heatmap uses imshow - first 2 dims are the x/y axes of the heatmap
+ # Only call assign_slots if we need to resolve 'auto' values
+ if facet_col == 'auto' or animation_frame == 'auto':
+ heatmap_axes = set(list(da.dims)[:2]) if len(da.dims) >= 2 else set()
+ slots = assign_slots(
+ self._ds,
+ x=None,
+ color=None,
+ facet_col=facet_col,
+ facet_row=None,
+ animation_frame=animation_frame,
+ exclude_dims=heatmap_axes,
+ )
+ resolved_facet = slots['facet_col']
+ resolved_animation = slots['animation_frame']
+ else:
+ # Values already resolved (or None), use directly without re-resolving
+ resolved_facet = facet_col
+ resolved_animation = animation_frame
+
+ imshow_args: dict[str, Any] = {
+ 'color_continuous_scale': colors,
+ 'title': title or variable,
+ }
+
+ if resolved_facet and resolved_facet in da.dims:
+ imshow_args['facet_col'] = resolved_facet
+ if facet_col_wrap < da.sizes[resolved_facet]:
+ imshow_args['facet_col_wrap'] = facet_col_wrap
+
+ if resolved_animation and resolved_animation in da.dims:
+ imshow_args['animation_frame'] = resolved_animation
+
+ # Squeeze singleton dimensions not used for faceting/animation
+ # px.imshow can't handle extra singleton dims in multi-dimensional data
+ dims_to_preserve = set(list(da.dims)[:2]) # First 2 dims are heatmap x/y axes
+ if resolved_facet and resolved_facet in da.dims:
+ dims_to_preserve.add(resolved_facet)
+ if resolved_animation and resolved_animation in da.dims:
+ dims_to_preserve.add(resolved_animation)
+ for dim in list(da.dims):
+ if dim not in dims_to_preserve and da.sizes[dim] == 1:
+ da = da.squeeze(dim)
+ imshow_args['img'] = da
+
+ # Use binary_string=False to handle non-numeric coords (e.g., string labels)
+ if 'binary_string' not in imshow_kwargs:
+ imshow_args['binary_string'] = False
+
+ return px.imshow(**{**imshow_args, **imshow_kwargs})
+
+ def scatter(
+ self,
+ x: str,
+ y: str,
+ *,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a scatter plot from two variables in the dataset.
+
+ Args:
+ x: Variable name for x-axis.
+ y: Variable name for y-axis.
+ title: Plot title.
+ xlabel: X-axis label.
+ ylabel: Y-axis label.
+ facet_col: Dimension for column facets. 'auto' uses CONFIG priority.
+ facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
+ facet_cols: Number of columns in facet grid wrap.
+ **px_kwargs: Additional arguments passed to plotly.express.scatter.
+
+ Returns:
+ Plotly Figure.
+ """
+ if x not in self._ds.data_vars:
+ raise ValueError(f"Variable '{x}' not found in dataset. Available: {list(self._ds.data_vars)}")
+ if y not in self._ds.data_vars:
+ raise ValueError(f"Variable '{y}' not found in dataset. Available: {list(self._ds.data_vars)}")
+
+ df = self._ds[[x, y]].to_dataframe().reset_index()
+ if df.empty:
+ return go.Figure()
+
+ # Scatter uses explicit x/y variable names, not dimensions
+ slots = assign_slots(
+ self._ds, x=None, color=None, facet_col=facet_col, facet_row=facet_row, animation_frame=animation_frame
+ )
+
+ facet_col_wrap = facet_cols or CONFIG.Plotting.default_facet_cols
+ fig_kwargs: dict[str, Any] = {
+ 'data_frame': df,
+ 'x': x,
+ 'y': y,
+ 'title': title,
+ **px_kwargs,
+ }
+ if xlabel:
+ fig_kwargs['labels'] = {**fig_kwargs.get('labels', {}), x: xlabel}
+ if ylabel:
+ fig_kwargs['labels'] = {**fig_kwargs.get('labels', {}), y: ylabel}
+
+ # Only use facets if the column actually exists in the dataframe
+ # (scatter uses wide format, so 'variable' column doesn't exist)
+ if slots['facet_col'] and slots['facet_col'] in df.columns:
+ fig_kwargs['facet_col'] = slots['facet_col']
+ if facet_col_wrap < self._ds.sizes.get(slots['facet_col'], facet_col_wrap + 1):
+ fig_kwargs['facet_col_wrap'] = facet_col_wrap
+ if slots['facet_row'] and slots['facet_row'] in df.columns:
+ fig_kwargs['facet_row'] = slots['facet_row']
+ if slots['animation_frame'] and slots['animation_frame'] in df.columns:
+ fig_kwargs['animation_frame'] = slots['animation_frame']
+
+ return px.scatter(**fig_kwargs)
+
+ def pie(
+ self,
+ *,
+ colors: ColorType | None = None,
+ title: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a pie chart from aggregated dataset values.
+
+ Extra dimensions are auto-assigned to facet_col and facet_row.
+ For scalar values, a single pie is shown.
+
+ Note:
+ ``px.pie()`` does not support animation_frame, so only facets are available.
+
+ Args:
+ colors: Color specification (colorscale name, color list, or dict mapping).
+ title: Plot title.
+ facet_col: Dimension for column facets. 'auto' uses CONFIG priority.
+ facet_row: Dimension for row facets. 'auto' uses CONFIG priority.
+ facet_cols: Number of columns in facet grid wrap.
+ **px_kwargs: Additional arguments passed to plotly.express.pie.
+
+ Returns:
+ Plotly Figure.
+
+ Example:
+ >>> ds.sum('time').fxplot.pie() # Sum over time, then pie chart
+ >>> ds.sum('time').fxplot.pie(facet_col='scenario') # Pie per scenario
+ """
+ max_ndim = max((self._ds[v].ndim for v in self._ds.data_vars), default=0)
+
+ names = list(self._ds.data_vars)
+ color_map = process_colors(colors, names, default_colorscale=CONFIG.Plotting.default_qualitative_colorscale)
+
+ # Scalar case - single pie
+ if max_ndim == 0:
+ values = [float(self._ds[v].values) for v in names]
+ df = pd.DataFrame({'variable': names, 'value': values})
+ return px.pie(
+ df,
+ names='variable',
+ values='value',
+ title=title,
+ color='variable',
+ color_discrete_map=color_map,
+ **px_kwargs,
+ )
+
+ # Multi-dimensional case - faceted pies (px.pie doesn't support animation_frame)
+ df = _dataset_to_long_df(self._ds)
+ if df.empty:
+ return go.Figure()
+
+ # Pie uses 'variable' for names and 'value' for values, no x/color/animation_frame
+ slots = assign_slots(
+ self._ds, x=None, color=None, facet_col=facet_col, facet_row=facet_row, animation_frame=None
+ )
+
+ facet_col_wrap = facet_cols or CONFIG.Plotting.default_facet_cols
+ fig_kwargs: dict[str, Any] = {
+ 'data_frame': df,
+ 'names': 'variable',
+ 'values': 'value',
+ 'title': title,
+ 'color': 'variable',
+ 'color_discrete_map': color_map,
+ **px_kwargs,
+ }
+
+ if slots['facet_col']:
+ fig_kwargs['facet_col'] = slots['facet_col']
+ if facet_col_wrap < self._ds.sizes.get(slots['facet_col'], facet_col_wrap + 1):
+ fig_kwargs['facet_col_wrap'] = facet_col_wrap
+ if slots['facet_row']:
+ fig_kwargs['facet_row'] = slots['facet_row']
+
+ return px.pie(**fig_kwargs)
+
+
+@xr.register_dataset_accessor('fxstats')
+class DatasetStatsAccessor:
+ """Statistics/transformation accessor for any xr.Dataset. Access via ``dataset.fxstats``.
+
+ Provides data transformation methods that return new datasets.
+ Chain with ``.fxplot`` for visualization.
+
+ Examples:
+ Duration curve::
+
+ ds.fxstats.to_duration_curve().fxplot.line()
+ """
+
+ def __init__(self, xarray_obj: xr.Dataset) -> None:
+ self._ds = xarray_obj
+
+ def to_duration_curve(self, *, normalize: bool = True) -> xr.Dataset:
+ """Transform dataset to duration curve format (sorted values).
+
+ Values are sorted in descending order along the 'time' dimension.
+ The time coordinate is replaced with duration (percentage or index).
+
+ Args:
+ normalize: If True, x-axis shows percentage (0-100). If False, shows timestep index.
+
+ Returns:
+ Transformed xr.Dataset with duration coordinate instead of time.
+
+ Example:
+ >>> ds.fxstats.to_duration_curve().fxplot.line(title='Duration Curve')
+ """
+ import numpy as np
+
+ if 'time' not in self._ds.dims:
+ raise ValueError("Duration curve requires a 'time' dimension.")
+
+ # Sort each variable along time dimension (descending)
+ sorted_ds = self._ds.copy()
+ for var in sorted_ds.data_vars:
+ da = sorted_ds[var]
+ time_axis = da.dims.index('time')
+ # Sort along time axis (descending) - use flip for correct axis
+ sorted_values = np.flip(np.sort(da.values, axis=time_axis), axis=time_axis)
+ sorted_ds[var] = (da.dims, sorted_values)
+
+ # Replace time coordinate with duration
+ n_timesteps = sorted_ds.sizes['time']
+ if normalize:
+ duration_coord = np.linspace(0, 100, n_timesteps)
+ sorted_ds = sorted_ds.assign_coords({'time': duration_coord})
+ sorted_ds = sorted_ds.rename({'time': 'duration_pct'})
+ else:
+ duration_coord = np.arange(n_timesteps)
+ sorted_ds = sorted_ds.assign_coords({'time': duration_coord})
+ sorted_ds = sorted_ds.rename({'time': 'duration'})
+
+ return sorted_ds
+
+
+@xr.register_dataarray_accessor('fxplot')
+class DataArrayPlotAccessor:
+ """Plot accessor for any xr.DataArray. Access via ``dataarray.fxplot``.
+
+ Provides convenient plotting methods. For bar/stacked_bar/line/area,
+ the DataArray is converted to a Dataset first. For heatmap, it works
+ directly with the DataArray.
+
+ Examples:
+ Basic usage::
+
+ import flixopt
+ import xarray as xr
+
+ da = xr.DataArray([1, 2, 3], dims=['time'], name='temperature')
+ da.fxplot.line()
+ da.fxplot.heatmap()
+ """
+
+ def __init__(self, xarray_obj: xr.DataArray) -> None:
+ """Initialize the accessor with an xr.DataArray object."""
+ self._da = xarray_obj
+
+ def _to_dataset(self) -> xr.Dataset:
+ """Convert DataArray to Dataset for plotting."""
+ name = self._da.name or 'value'
+ return self._da.to_dataset(name=name)
+
+ def bar(
+ self,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ colors: ColorType | None = None,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a grouped bar chart. See DatasetPlotAccessor.bar for details."""
+ return self._to_dataset().fxplot.bar(
+ x=x,
+ colors=colors,
+ title=title,
+ xlabel=xlabel,
+ ylabel=ylabel,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ facet_cols=facet_cols,
+ **px_kwargs,
+ )
+
+ def stacked_bar(
+ self,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ colors: ColorType | None = None,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ exclude_dims: set[str] | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a stacked bar chart. See DatasetPlotAccessor.stacked_bar for details."""
+ return self._to_dataset().fxplot.stacked_bar(
+ x=x,
+ colors=colors,
+ title=title,
+ xlabel=xlabel,
+ ylabel=ylabel,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ facet_cols=facet_cols,
+ **px_kwargs,
+ )
+
+ def line(
+ self,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ colors: ColorType | None = None,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ line_shape: str | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a line chart. See DatasetPlotAccessor.line for details."""
+ return self._to_dataset().fxplot.line(
+ x=x,
+ colors=colors,
+ title=title,
+ xlabel=xlabel,
+ ylabel=ylabel,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ facet_cols=facet_cols,
+ line_shape=line_shape,
+ **px_kwargs,
+ )
+
+ def area(
+ self,
+ *,
+ x: str | Literal['auto'] | None = 'auto',
+ colors: ColorType | None = None,
+ title: str = '',
+ xlabel: str = '',
+ ylabel: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ line_shape: str | None = None,
+ **px_kwargs: Any,
+ ) -> go.Figure:
+ """Create a stacked area chart. See DatasetPlotAccessor.area for details."""
+ return self._to_dataset().fxplot.area(
+ x=x,
+ colors=colors,
+ title=title,
+ xlabel=xlabel,
+ ylabel=ylabel,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
+ facet_cols=facet_cols,
+ line_shape=line_shape,
+ **px_kwargs,
+ )
+
+ def heatmap(
+ self,
+ *,
+ colors: str | list[str] | None = None,
+ title: str = '',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
+ facet_cols: int | None = None,
+ **imshow_kwargs: Any,
+ ) -> go.Figure:
+ """Create a heatmap visualization directly from the DataArray.
+
+ Args:
+ colors: Colorscale name or list of colors.
+ title: Plot title.
+ facet_col: Dimension for column facets.
+ animation_frame: Dimension for animation slider.
+ facet_cols: Number of columns in facet grid wrap.
+ **imshow_kwargs: Additional arguments passed to plotly.express.imshow.
+
+ Returns:
+ Plotly Figure.
+ """
+ da = self._da
+
+ if da.size == 0:
+ return go.Figure()
+
+ colors = colors or CONFIG.Plotting.default_sequential_colorscale
+ facet_col_wrap = facet_cols or CONFIG.Plotting.default_facet_cols
+
+ # Heatmap uses imshow - first 2 dims are the x/y axes of the heatmap
+ # Only call assign_slots if we need to resolve 'auto' values
+ if facet_col == 'auto' or animation_frame == 'auto':
+ heatmap_axes = set(list(da.dims)[:2]) if len(da.dims) >= 2 else set()
+ ds_for_resolution = da.to_dataset(name='_temp')
+ slots = assign_slots(
+ ds_for_resolution,
+ x=None,
+ color=None,
+ facet_col=facet_col,
+ facet_row=None,
+ animation_frame=animation_frame,
+ exclude_dims=heatmap_axes,
+ )
+ resolved_facet = slots['facet_col']
+ resolved_animation = slots['animation_frame']
+ else:
+ # Values already resolved (or None), use directly without re-resolving
+ resolved_facet = facet_col
+ resolved_animation = animation_frame
+
+ imshow_args: dict[str, Any] = {
+ 'color_continuous_scale': colors,
+ 'title': title or (da.name if da.name else ''),
+ }
+
+ if resolved_facet and resolved_facet in da.dims:
+ imshow_args['facet_col'] = resolved_facet
+ if facet_col_wrap < da.sizes[resolved_facet]:
+ imshow_args['facet_col_wrap'] = facet_col_wrap
+
+ if resolved_animation and resolved_animation in da.dims:
+ imshow_args['animation_frame'] = resolved_animation
+
+ # Squeeze singleton dimensions not used for faceting/animation
+ # px.imshow can't handle extra singleton dims in multi-dimensional data
+ dims_to_preserve = set(list(da.dims)[:2]) # First 2 dims are heatmap x/y axes
+ if resolved_facet and resolved_facet in da.dims:
+ dims_to_preserve.add(resolved_facet)
+ if resolved_animation and resolved_animation in da.dims:
+ dims_to_preserve.add(resolved_animation)
+ for dim in list(da.dims):
+ if dim not in dims_to_preserve and da.sizes[dim] == 1:
+ da = da.squeeze(dim)
+ imshow_args['img'] = da
+
+ # Use binary_string=False to handle non-numeric coords (e.g., string labels)
+ if 'binary_string' not in imshow_kwargs:
+ imshow_args['binary_string'] = False
+
+ return px.imshow(**{**imshow_args, **imshow_kwargs})
diff --git a/flixopt/effects.py b/flixopt/effects.py
index cdac7ca7d..3a2322988 100644
--- a/flixopt/effects.py
+++ b/flixopt/effects.py
@@ -252,7 +252,6 @@ def transform_data(self) -> None:
prefix=None,
effect_values=self.share_from_temporal,
suffix=f'(temporal)->{self.prefix}(temporal)',
- dims=['time', 'period', 'scenario'],
)
self.share_from_periodic = self._fit_effect_coords(
prefix=None,
diff --git a/flixopt/elements.py b/flixopt/elements.py
index 2933eb95a..0cee53738 100644
--- a/flixopt/elements.py
+++ b/flixopt/elements.py
@@ -680,7 +680,7 @@ def _do_modeling(self):
ModelingPrimitives.expression_tracking_variable(
model=self,
name=f'{self.label_full}|total_flow_hours',
- tracked_expression=(self.flow_rate * self._model.hours_per_step).sum('time'),
+ tracked_expression=self._model.sum_temporal(self.flow_rate),
bounds=(
self.element.flow_hours_min if self.element.flow_hours_min is not None else 0,
self.element.flow_hours_max if self.element.flow_hours_max is not None else None,
@@ -821,12 +821,12 @@ def results_structure(self):
}
def _create_shares(self):
- # Effects per flow hour
+ # Effects per flow hour (use timestep_duration only, cluster_weight is applied when summing to total)
if self.element.effects_per_flow_hour:
self._model.effects.add_share_to_effects(
name=self.label_full,
expressions={
- effect: self.flow_rate * self._model.hours_per_step * factor
+ effect: self.flow_rate * self._model.timestep_duration * factor
for effect, factor in self.element.effects_per_flow_hour.items()
},
target='temporal',
@@ -837,9 +837,12 @@ def _create_bounds_for_load_factor(self):
# Get the size (either from element or investment)
size = self.investment.size if self.with_investment else self.element.size
+ # Total hours in the period (sum of temporal weights)
+ total_hours = self._model.temporal_weight.sum(self._model.temporal_dims)
+
# Maximum load factor constraint
if self.element.load_factor_max is not None:
- flow_hours_per_size_max = self._model.hours_per_step.sum('time') * self.element.load_factor_max
+ flow_hours_per_size_max = total_hours * self.element.load_factor_max
self.add_constraints(
self.total_flow_hours <= size * flow_hours_per_size_max,
short_name='load_factor_max',
@@ -847,7 +850,7 @@ def _create_bounds_for_load_factor(self):
# Minimum load factor constraint
if self.element.load_factor_min is not None:
- flow_hours_per_size_min = self._model.hours_per_step.sum('time') * self.element.load_factor_min
+ flow_hours_per_size_min = total_hours * self.element.load_factor_min
self.add_constraints(
self.total_flow_hours >= size * flow_hours_per_size_min,
short_name='load_factor_min',
@@ -951,7 +954,7 @@ def _do_modeling(self):
# Add virtual supply/demand to balance and penalty if needed
if self.element.allows_imbalance:
- imbalance_penalty = np.multiply(self._model.hours_per_step, self.element.imbalance_penalty_per_flow_hour)
+ imbalance_penalty = self.element.imbalance_penalty_per_flow_hour * self._model.timestep_duration
self.virtual_supply = self.add_variables(
lower=0, coords=self._model.get_coords(), short_name='virtual_supply'
diff --git a/flixopt/features.py b/flixopt/features.py
index 4dfe48964..289640ddd 100644
--- a/flixopt/features.py
+++ b/flixopt/features.py
@@ -196,15 +196,14 @@ def _do_modeling(self):
inactive = self.add_variables(binary=True, short_name='inactive', coords=self._model.get_coords())
self.add_constraints(self.status + inactive == 1, short_name='complementary')
- # 3. Total duration tracking using existing pattern
+ # 3. Total duration tracking
+ total_hours = self._model.temporal_weight.sum(self._model.temporal_dims)
ModelingPrimitives.expression_tracking_variable(
self,
- tracked_expression=(self.status * self._model.hours_per_step).sum('time'),
+ tracked_expression=self._model.sum_temporal(self.status),
bounds=(
self.parameters.active_hours_min if self.parameters.active_hours_min is not None else 0,
- self.parameters.active_hours_max
- if self.parameters.active_hours_max is not None
- else self._model.hours_per_step.sum('time').max().item(),
+ self.parameters.active_hours_max if self.parameters.active_hours_max is not None else total_hours,
),
short_name='active_hours',
coords=['period', 'scenario'],
@@ -232,7 +231,9 @@ def _do_modeling(self):
coords=self._model.get_coords(('period', 'scenario')),
short_name='startup_count',
)
- self.add_constraints(count == self.startup.sum('time'), short_name='startup_count')
+ # Sum over all temporal dimensions (time, and cluster if present)
+ startup_temporal_dims = [d for d in self.startup.dims if d not in ('period', 'scenario')]
+ self.add_constraints(count == self.startup.sum(startup_temporal_dims), short_name='startup_count')
# 5. Consecutive active duration (uptime) using existing pattern
if self.parameters.use_uptime_tracking:
@@ -242,7 +243,7 @@ def _do_modeling(self):
short_name='uptime',
minimum_duration=self.parameters.min_uptime,
maximum_duration=self.parameters.max_uptime,
- duration_per_step=self.hours_per_step,
+ duration_per_step=self.timestep_duration,
duration_dim='time',
previous_duration=self._get_previous_uptime(),
)
@@ -255,7 +256,7 @@ def _do_modeling(self):
short_name='downtime',
minimum_duration=self.parameters.min_downtime,
maximum_duration=self.parameters.max_downtime,
- duration_per_step=self.hours_per_step,
+ duration_per_step=self.timestep_duration,
duration_dim='time',
previous_duration=self._get_previous_downtime(),
)
@@ -263,12 +264,12 @@ def _do_modeling(self):
self._add_effects()
def _add_effects(self):
- """Add operational effects"""
+ """Add operational effects (use timestep_duration only, cluster_weight is applied when summing to total)"""
if self.parameters.effects_per_active_hour:
self._model.effects.add_share_to_effects(
name=self.label_of_element,
expressions={
- effect: self.status * factor * self._model.hours_per_step
+ effect: self.status * factor * self._model.timestep_duration
for effect, factor in self.parameters.effects_per_active_hour.items()
},
target='temporal',
@@ -330,7 +331,7 @@ def _get_previous_uptime(self):
Returns 0 if no previous status is provided (assumes previously inactive).
"""
- hours_per_step = self._model.hours_per_step.isel(time=0).min().item()
+ hours_per_step = self._model.timestep_duration.isel(time=0).min().item()
if self._previous_status is None:
return 0
else:
@@ -341,7 +342,7 @@ def _get_previous_downtime(self):
Returns one timestep duration if no previous status is provided (assumes previously inactive).
"""
- hours_per_step = self._model.hours_per_step.isel(time=0).min().item()
+ hours_per_step = self._model.timestep_duration.isel(time=0).min().item()
if self._previous_status is None:
return hours_per_step
else:
@@ -612,16 +613,18 @@ def _do_modeling(self):
if 'time' in self._dims:
self.total_per_timestep = self.add_variables(
- lower=-np.inf if (self._min_per_hour is None) else self._min_per_hour * self._model.hours_per_step,
- upper=np.inf if (self._max_per_hour is None) else self._max_per_hour * self._model.hours_per_step,
+ lower=-np.inf if (self._min_per_hour is None) else self._min_per_hour * self._model.timestep_duration,
+ upper=np.inf if (self._max_per_hour is None) else self._max_per_hour * self._model.timestep_duration,
coords=self._model.get_coords(self._dims),
short_name='per_timestep',
)
self._eq_total_per_timestep = self.add_constraints(self.total_per_timestep == 0, short_name='per_timestep')
- # Add it to the total
- self._eq_total.lhs -= self.total_per_timestep.sum(dim='time')
+ # Add it to the total (cluster_weight handles cluster representation, defaults to 1.0)
+ # Sum over all temporal dimensions (time, and cluster if present)
+ weighted_per_timestep = self.total_per_timestep * self._model.weights.get('cluster', 1.0)
+ self._eq_total.lhs -= weighted_per_timestep.sum(dim=self._model.temporal_dims)
def add_share(
self,
diff --git a/flixopt/flow_system.py b/flixopt/flow_system.py
index 13821b35b..7e12029ed 100644
--- a/flixopt/flow_system.py
+++ b/flixopt/flow_system.py
@@ -38,11 +38,17 @@
import pyvis
+ from .clustering import Clustering
from .solvers import _Solver
from .types import Effect_TPS, Numeric_S, Numeric_TPS, NumericOrBool
from .carrier import Carrier, CarrierContainer
+# Register clustering classes for IO (deferred to avoid circular imports)
+from .clustering.base import _register_clustering_classes
+
+_register_clustering_classes()
+
logger = logging.getLogger('flixopt')
@@ -65,8 +71,12 @@ class FlowSystem(Interface, CompositeContainerMixin[Element]):
weight_of_last_period: Weight/duration of the last period. If None, computed from the last period interval.
Used for calculating sums over periods in multi-period models.
scenario_weights: The weights of each scenario. If None, all scenarios have the same weight (normalized to 1).
- Period weights are always computed internally from the period index (like hours_per_timestep for time).
+ Period weights are always computed internally from the period index (like timestep_duration for time).
The final `weights` array (accessible via `flow_system.model.objective_weights`) is computed as period_weights Γ normalized_scenario_weights, with normalization applied to the scenario weights by default.
+ cluster_weight: Weight for each cluster.
+ If None (default), all clusters have weight 1.0. Used by cluster() to specify
+ how many original timesteps each cluster represents. Multiply with timestep_duration
+ for proper time aggregation in clustered models.
scenario_independent_sizes: Controls whether investment sizes are equalized across scenarios.
- True: All sizes are shared/equalized across scenarios
- False: All sizes are optimized separately per scenario
@@ -166,10 +176,12 @@ def __init__(
timesteps: pd.DatetimeIndex,
periods: pd.Index | None = None,
scenarios: pd.Index | None = None,
+ clusters: pd.Index | None = None,
hours_of_last_timestep: int | float | None = None,
hours_of_previous_timesteps: int | float | np.ndarray | None = None,
weight_of_last_period: int | float | None = None,
scenario_weights: Numeric_S | None = None,
+ cluster_weight: Numeric_TPS | None = None,
scenario_independent_sizes: bool | list[str] = True,
scenario_independent_flow_rates: bool | list[str] = False,
name: str | None = None,
@@ -181,13 +193,26 @@ def __init__(
self.timesteps_extra,
self.hours_of_last_timestep,
self.hours_of_previous_timesteps,
- hours_per_timestep,
+ timestep_duration,
) = self._compute_time_metadata(self.timesteps, hours_of_last_timestep, hours_of_previous_timesteps)
self.periods = None if periods is None else self._validate_periods(periods)
self.scenarios = None if scenarios is None else self._validate_scenarios(scenarios)
+ self.clusters = clusters # Cluster dimension for clustered FlowSystems
- self.hours_per_timestep = self.fit_to_model_coords('hours_per_timestep', hours_per_timestep)
+ self.timestep_duration = self.fit_to_model_coords('timestep_duration', timestep_duration)
+
+ # Cluster weight for cluster() optimization (default 1.0)
+ # Represents how many original timesteps each cluster represents
+ # May have period/scenario dimensions if cluster() was used with those
+ self.cluster_weight: xr.DataArray | None = (
+ self.fit_to_model_coords(
+ 'cluster_weight',
+ cluster_weight,
+ )
+ if cluster_weight is not None
+ else None
+ )
self.scenario_weights = scenario_weights # Use setter
@@ -216,8 +241,8 @@ def __init__(
# Solution dataset - populated after optimization or loaded from file
self._solution: xr.Dataset | None = None
- # Clustering info - populated by transform.cluster()
- self._clustering_info: dict | None = None
+ # Aggregation info - populated by transform.cluster()
+ self.clustering: Clustering | None = None
# Statistics accessor cache - lazily initialized, invalidated on new solution
self._statistics: StatisticsAccessor | None = None
@@ -302,11 +327,11 @@ def _create_timesteps_with_extra(
return pd.DatetimeIndex(timesteps.append(last_date), name='time')
@staticmethod
- def calculate_hours_per_timestep(timesteps_extra: pd.DatetimeIndex) -> xr.DataArray:
- """Calculate duration of each timestep as a 1D DataArray."""
+ def calculate_timestep_duration(timesteps_extra: pd.DatetimeIndex) -> xr.DataArray:
+ """Calculate duration of each timestep in hours as a 1D DataArray."""
hours_per_step = np.diff(timesteps_extra) / pd.Timedelta(hours=1)
return xr.DataArray(
- hours_per_step, coords={'time': timesteps_extra[:-1]}, dims='time', name='hours_per_timestep'
+ hours_per_step, coords={'time': timesteps_extra[:-1]}, dims='time', name='timestep_duration'
)
@staticmethod
@@ -377,22 +402,22 @@ def _compute_time_metadata(
Can be a scalar or array.
Returns:
- Tuple of (timesteps_extra, hours_of_last_timestep, hours_of_previous_timesteps, hours_per_timestep)
+ Tuple of (timesteps_extra, hours_of_last_timestep, hours_of_previous_timesteps, timestep_duration)
"""
# Create timesteps with extra step at the end
timesteps_extra = cls._create_timesteps_with_extra(timesteps, hours_of_last_timestep)
- # Calculate hours per timestep
- hours_per_timestep = cls.calculate_hours_per_timestep(timesteps_extra)
+ # Calculate timestep duration
+ timestep_duration = cls.calculate_timestep_duration(timesteps_extra)
# Extract hours_of_last_timestep if not provided
if hours_of_last_timestep is None:
- hours_of_last_timestep = hours_per_timestep.isel(time=-1).item()
+ hours_of_last_timestep = timestep_duration.isel(time=-1).item()
# Compute hours_of_previous_timesteps (handles both None and provided cases)
hours_of_previous_timesteps = cls._calculate_hours_of_previous_timesteps(timesteps, hours_of_previous_timesteps)
- return timesteps_extra, hours_of_last_timestep, hours_of_previous_timesteps, hours_per_timestep
+ return timesteps_extra, hours_of_last_timestep, hours_of_previous_timesteps, timestep_duration
@classmethod
def _compute_period_metadata(
@@ -437,7 +462,7 @@ def _update_time_metadata(
"""
Update time-related attributes and data variables in dataset based on its time index.
- Recomputes hours_of_last_timestep, hours_of_previous_timesteps, and hours_per_timestep
+ Recomputes hours_of_last_timestep, hours_of_previous_timesteps, and timestep_duration
from the dataset's time index when these parameters are None. This ensures time metadata
stays synchronized with the actual timesteps after operations like resampling or selection.
@@ -453,14 +478,14 @@ def _update_time_metadata(
new_time_index = dataset.indexes.get('time')
if new_time_index is not None and len(new_time_index) >= 2:
# Use shared helper to compute all time metadata
- _, hours_of_last_timestep, hours_of_previous_timesteps, hours_per_timestep = cls._compute_time_metadata(
+ _, hours_of_last_timestep, hours_of_previous_timesteps, timestep_duration = cls._compute_time_metadata(
new_time_index, hours_of_last_timestep, hours_of_previous_timesteps
)
- # Update hours_per_timestep DataArray if it exists in the dataset
+ # Update timestep_duration DataArray if it exists in the dataset
# This prevents stale data after resampling operations
- if 'hours_per_timestep' in dataset.data_vars:
- dataset['hours_per_timestep'] = hours_per_timestep
+ if 'timestep_duration' in dataset.data_vars:
+ dataset['timestep_duration'] = timestep_duration
# Update time-related attributes only when new values are provided/computed
# This preserves existing metadata instead of overwriting with None
@@ -484,6 +509,9 @@ def _update_period_metadata(
period index. This ensures period metadata stays synchronized with the actual
periods after operations like selection.
+ When the period dimension is dropped (single value selected), this method
+ removes the scalar coordinate, period_weights DataArray, and cleans up attributes.
+
This is analogous to _update_time_metadata() for time-related metadata.
Args:
@@ -495,7 +523,16 @@ def _update_period_metadata(
The same dataset with updated period-related attributes and data variables
"""
new_period_index = dataset.indexes.get('period')
- if new_period_index is not None and len(new_period_index) >= 1:
+
+ if new_period_index is None:
+ # Period dimension was dropped (single value selected)
+ if 'period' in dataset.coords:
+ dataset = dataset.drop_vars('period')
+ dataset = dataset.drop_vars(['period_weights'], errors='ignore')
+ dataset.attrs.pop('weight_of_last_period', None)
+ return dataset
+
+ if len(new_period_index) >= 1:
# Reuse stored weight_of_last_period when not explicitly overridden.
# This is essential for single-period subsets where it cannot be inferred from intervals.
if weight_of_last_period is None:
@@ -524,6 +561,9 @@ def _update_scenario_metadata(cls, dataset: xr.Dataset) -> xr.Dataset:
Recomputes or removes scenario weights. This ensures scenario metadata stays synchronized with the actual
scenarios after operations like selection.
+ When the scenario dimension is dropped (single value selected), this method
+ removes the scalar coordinate, scenario_weights DataArray, and cleans up attributes.
+
This is analogous to _update_period_metadata() for time-related metadata.
Args:
@@ -533,7 +573,16 @@ def _update_scenario_metadata(cls, dataset: xr.Dataset) -> xr.Dataset:
The same dataset with updated scenario-related attributes and data variables
"""
new_scenario_index = dataset.indexes.get('scenario')
- if new_scenario_index is None or len(new_scenario_index) <= 1:
+
+ if new_scenario_index is None:
+ # Scenario dimension was dropped (single value selected)
+ if 'scenario' in dataset.coords:
+ dataset = dataset.drop_vars('scenario')
+ dataset = dataset.drop_vars(['scenario_weights'], errors='ignore')
+ dataset.attrs.pop('scenario_weights', None)
+ return dataset
+
+ if len(new_scenario_index) <= 1:
dataset.attrs.pop('scenario_weights', None)
return dataset
@@ -627,6 +676,21 @@ def to_dataset(self, include_solution: bool = True) -> xr.Dataset:
carriers_structure[name] = carrier_ref
ds.attrs['carriers'] = json.dumps(carriers_structure)
+ # Include cluster info for clustered FlowSystems (old structure)
+ if self.clusters is not None:
+ ds.attrs['is_clustered'] = True
+ ds.attrs['n_clusters'] = len(self.clusters)
+ ds.attrs['timesteps_per_cluster'] = len(self.timesteps)
+ ds.attrs['timestep_duration'] = float(self.timestep_duration.mean())
+
+ # Serialize Clustering object if present (new structure)
+ if self.clustering is not None:
+ clustering_ref, clustering_arrays = self.clustering._create_reference_structure()
+ # Add clustering arrays with prefix
+ for name, arr in clustering_arrays.items():
+ ds[f'clustering|{name}'] = arr
+ ds.attrs['clustering'] = json.dumps(clustering_ref)
+
# Add version info
ds.attrs['flixopt_version'] = __version__
@@ -642,6 +706,10 @@ def from_dataset(cls, ds: xr.Dataset) -> FlowSystem:
the solution will be restored to the FlowSystem. Solution time coordinates
are renamed back from 'solution_time' to 'time'.
+ Supports clustered datasets with (cluster, time) dimensions. When detected,
+ creates a synthetic DatetimeIndex for compatibility and stores the clustered
+ data structure for later use.
+
Args:
ds: Dataset containing the FlowSystem data
@@ -666,17 +734,35 @@ def from_dataset(cls, ds: xr.Dataset) -> FlowSystem:
# Create arrays dictionary from config variables only
arrays_dict = config_vars
+ # Extract cluster index if present (clustered FlowSystem)
+ clusters = ds.indexes.get('cluster')
+
+ # For clustered datasets, cluster_weight is (cluster,) shaped - set separately
+ if clusters is not None:
+ cluster_weight_for_constructor = None
+ else:
+ cluster_weight_for_constructor = (
+ cls._resolve_dataarray_reference(reference_structure['cluster_weight'], arrays_dict)
+ if 'cluster_weight' in reference_structure
+ else None
+ )
+
+ # Resolve scenario_weights only if scenario dimension exists
+ scenario_weights = None
+ if ds.indexes.get('scenario') is not None and 'scenario_weights' in reference_structure:
+ scenario_weights = cls._resolve_dataarray_reference(reference_structure['scenario_weights'], arrays_dict)
+
# Create FlowSystem instance with constructor parameters
flow_system = cls(
timesteps=ds.indexes['time'],
periods=ds.indexes.get('period'),
scenarios=ds.indexes.get('scenario'),
+ clusters=clusters,
hours_of_last_timestep=reference_structure.get('hours_of_last_timestep'),
hours_of_previous_timesteps=reference_structure.get('hours_of_previous_timesteps'),
weight_of_last_period=reference_structure.get('weight_of_last_period'),
- scenario_weights=cls._resolve_dataarray_reference(reference_structure['scenario_weights'], arrays_dict)
- if 'scenario_weights' in reference_structure
- else None,
+ scenario_weights=scenario_weights,
+ cluster_weight=cluster_weight_for_constructor,
scenario_independent_sizes=reference_structure.get('scenario_independent_sizes', True),
scenario_independent_flow_rates=reference_structure.get('scenario_independent_flow_rates', False),
name=reference_structure.get('name'),
@@ -721,6 +807,19 @@ def from_dataset(cls, ds: xr.Dataset) -> FlowSystem:
carrier = cls._resolve_reference_structure(carrier_data, {})
flow_system._carriers.add(carrier)
+ # Restore Clustering object if present
+ if 'clustering' in reference_structure:
+ clustering_structure = json.loads(reference_structure['clustering'])
+ # Collect clustering arrays (prefixed with 'clustering|')
+ clustering_arrays = {}
+ for name, arr in ds.data_vars.items():
+ if name.startswith('clustering|'):
+ # Remove 'clustering|' prefix (11 chars)
+ arr_name = name[11:]
+ clustering_arrays[arr_name] = arr
+ clustering = cls._resolve_reference_structure(clustering_structure, clustering_arrays)
+ flow_system.clustering = clustering
+
# Reconnect network to populate bus inputs/outputs (not stored in NetCDF).
flow_system.connect_and_transform()
@@ -1017,6 +1116,7 @@ def connect_and_transform(self):
self._connect_network()
self._register_missing_carriers()
self._assign_element_colors()
+
for element in chain(self.components.values(), self.effects.values(), self.buses.values()):
element.transform_data()
@@ -1230,22 +1330,29 @@ def flow_carriers(self) -> dict[str, str]:
return self._flow_carriers
- def create_model(self, normalize_weights: bool = True) -> FlowSystemModel:
+ def create_model(self, normalize_weights: bool | None = None) -> FlowSystemModel:
"""
Create a linopy model from the FlowSystem.
Args:
- normalize_weights: Whether to automatically normalize the weights (periods and scenarios) to sum up to 1 when solving.
+ normalize_weights: Deprecated. Scenario weights are now always normalized in FlowSystem.
"""
+ if normalize_weights is not None:
+ warnings.warn(
+ f'\n\nnormalize_weights parameter is deprecated and will be removed in {DEPRECATION_REMOVAL_VERSION}. '
+ 'Scenario weights are now always normalized when set on FlowSystem.\n',
+ DeprecationWarning,
+ stacklevel=2,
+ )
if not self.connected_and_transformed:
raise RuntimeError(
'FlowSystem is not connected_and_transformed. Call FlowSystem.connect_and_transform() first.'
)
# System integrity was already validated in connect_and_transform()
- self.model = FlowSystemModel(self, normalize_weights)
+ self.model = FlowSystemModel(self)
return self.model
- def build_model(self, normalize_weights: bool = True) -> FlowSystem:
+ def build_model(self, normalize_weights: bool | None = None) -> FlowSystem:
"""
Build the optimization model for this FlowSystem.
@@ -1253,12 +1360,13 @@ def build_model(self, normalize_weights: bool = True) -> FlowSystem:
1. Connecting and transforming all elements (if not already done)
2. Creating the FlowSystemModel with all variables and constraints
3. Adding clustering constraints (if this is a clustered FlowSystem)
+ 4. Adding typical periods modeling (if this is a reduced FlowSystem)
After calling this method, `self.model` will be available for inspection
before solving.
Args:
- normalize_weights: Whether to normalize scenario/period weights to sum to 1.
+ normalize_weights: Deprecated. Scenario weights are now always normalized in FlowSystem.
Returns:
Self, for method chaining.
@@ -1268,35 +1376,20 @@ def build_model(self, normalize_weights: bool = True) -> FlowSystem:
>>> print(flow_system.model.variables) # Inspect variables before solving
>>> flow_system.solve(solver)
"""
+ if normalize_weights is not None:
+ warnings.warn(
+ f'\n\nnormalize_weights parameter is deprecated and will be removed in {DEPRECATION_REMOVAL_VERSION}. '
+ 'Scenario weights are now always normalized when set on FlowSystem.\n',
+ DeprecationWarning,
+ stacklevel=2,
+ )
self.connect_and_transform()
- self.create_model(normalize_weights)
- self.model.do_modeling()
+ self.create_model()
- # Add clustering constraints if this is a clustered FlowSystem
- if self._clustering_info is not None:
- self._add_clustering_constraints()
+ self.model.do_modeling()
return self
- def _add_clustering_constraints(self) -> None:
- """Add clustering constraints to the model."""
- from .clustering import ClusteringModel
-
- info = self._clustering_info or {}
- required_keys = {'parameters', 'clustering', 'components_to_clusterize'}
- missing_keys = required_keys - set(info)
- if missing_keys:
- raise KeyError(f'_clustering_info missing required keys: {sorted(missing_keys)}')
-
- clustering_model = ClusteringModel(
- model=self.model,
- clustering_parameters=info['parameters'],
- flow_system=self,
- clustering_data=info['clustering'],
- components_to_clusterize=info['components_to_clusterize'],
- )
- clustering_model.do_modeling()
-
def solve(self, solver: _Solver) -> FlowSystem:
"""
Solve the optimization model and populate the solution.
@@ -1840,13 +1933,111 @@ def storages(self) -> ElementContainer[Storage]:
return self._storages_cache
@property
- def coords(self) -> dict[FlowSystemDimensions, pd.Index]:
- active_coords = {'time': self.timesteps}
+ def dims(self) -> list[str]:
+ """Active dimension names.
+
+ Returns:
+ List of active dimension names in order.
+
+ Example:
+ >>> fs.dims
+ ['time'] # simple case
+ >>> fs_clustered.dims
+ ['cluster', 'time', 'period', 'scenario'] # full case
+ """
+ result = []
+ if self.clusters is not None:
+ result.append('cluster')
+ result.append('time')
if self.periods is not None:
- active_coords['period'] = self.periods
+ result.append('period')
if self.scenarios is not None:
- active_coords['scenario'] = self.scenarios
- return active_coords
+ result.append('scenario')
+ return result
+
+ @property
+ def indexes(self) -> dict[str, pd.Index]:
+ """Indexes for active dimensions.
+
+ Returns:
+ Dict mapping dimension names to pandas Index objects.
+
+ Example:
+ >>> fs.indexes['time']
+ DatetimeIndex(['2024-01-01', ...], dtype='datetime64[ns]', name='time')
+ """
+ result: dict[str, pd.Index] = {}
+ if self.clusters is not None:
+ result['cluster'] = self.clusters
+ result['time'] = self.timesteps
+ if self.periods is not None:
+ result['period'] = self.periods
+ if self.scenarios is not None:
+ result['scenario'] = self.scenarios
+ return result
+
+ @property
+ def temporal_dims(self) -> list[str]:
+ """Temporal dimensions for summing over time.
+
+ Returns ['time', 'cluster'] for clustered systems, ['time'] otherwise.
+ """
+ if self.clusters is not None:
+ return ['time', 'cluster']
+ return ['time']
+
+ @property
+ def temporal_weight(self) -> xr.DataArray:
+ """Combined temporal weight (timestep_duration Γ cluster_weight).
+
+ Use for converting rates to totals before summing.
+ Note: cluster_weight is used even without a clusters dimension.
+ """
+ # Use cluster_weight directly if set, otherwise check weights dict, fallback to 1.0
+ cluster_weight = self.weights.get('cluster', self.cluster_weight if self.cluster_weight is not None else 1.0)
+ return self.weights['time'] * cluster_weight
+
+ @property
+ def coords(self) -> dict[FlowSystemDimensions, pd.Index]:
+ """Active coordinates for variable creation.
+
+ .. deprecated::
+ Use :attr:`indexes` instead.
+
+ Returns a dict of dimension names to coordinate arrays. When clustered,
+ includes 'cluster' dimension before 'time'.
+
+ Returns:
+ Dict mapping dimension names to coordinate arrays.
+ """
+ return self.indexes
+
+ @property
+ def _use_true_cluster_dims(self) -> bool:
+ """Check if true (cluster, time) dimensions should be used."""
+ return self.clusters is not None
+
+ @property
+ def _cluster_n_clusters(self) -> int | None:
+ """Get number of clusters."""
+ return len(self.clusters) if self.clusters is not None else None
+
+ @property
+ def _cluster_timesteps_per_cluster(self) -> int | None:
+ """Get timesteps per cluster (same as len(timesteps) for clustered systems)."""
+ return len(self.timesteps) if self.clusters is not None else None
+
+ @property
+ def _cluster_time_coords(self) -> pd.DatetimeIndex | None:
+ """Get time coordinates for clustered system (same as timesteps)."""
+ return self.timesteps if self.clusters is not None else None
+
+ @property
+ def n_timesteps(self) -> int:
+ """Number of timesteps (within each cluster if clustered)."""
+ if self.is_clustered:
+ return self.clustering.timesteps_per_cluster
+ return len(self.timesteps)
@property
def used_in_calculation(self) -> bool:
@@ -1865,14 +2056,15 @@ def scenario_weights(self) -> xr.DataArray | None:
@scenario_weights.setter
def scenario_weights(self, value: Numeric_S | None) -> None:
"""
- Set scenario weights.
+ Set scenario weights (always normalized to sum to 1).
Args:
- value: Scenario weights to set (will be converted to DataArray with 'scenario' dimension)
- or None to clear weights.
+ value: Scenario weights to set (will be converted to DataArray with 'scenario' dimension
+ and normalized to sum to 1), or None to clear weights.
Raises:
ValueError: If value is not None and no scenarios are defined in the FlowSystem.
+ ValueError: If weights sum to zero (cannot normalize).
"""
if value is None:
self._scenario_weights = None
@@ -1884,7 +2076,82 @@ def scenario_weights(self, value: Numeric_S | None) -> None:
'Either define scenarios in FlowSystem(scenarios=...) or set scenario_weights to None.'
)
- self._scenario_weights = self.fit_to_model_coords('scenario_weights', value, dims=['scenario'])
+ weights = self.fit_to_model_coords('scenario_weights', value, dims=['scenario'])
+
+ # Normalize to sum to 1
+ norm = weights.sum('scenario')
+ if np.isclose(norm, 0.0).any():
+ raise ValueError('scenario_weights sum to 0; cannot normalize.')
+ self._scenario_weights = weights / norm
+
+ def _unit_weight(self, dim: str) -> xr.DataArray:
+ """Create a unit weight DataArray (all 1.0) for a dimension."""
+ index = self.indexes[dim]
+ return xr.DataArray(
+ np.ones(len(index), dtype=float),
+ coords={dim: index},
+ dims=[dim],
+ name=f'{dim}_weight',
+ )
+
+ @property
+ def weights(self) -> dict[str, xr.DataArray]:
+ """Weights for active dimensions (unit weights if not explicitly set).
+
+ Returns:
+ Dict mapping dimension names to weight DataArrays.
+ Keys match :attr:`dims` and :attr:`indexes`.
+
+ Example:
+ >>> fs.weights['time'] # timestep durations
+ >>> fs.weights['cluster'] # cluster weights (unit if not set)
+ """
+ result: dict[str, xr.DataArray] = {'time': self.timestep_duration}
+ if self.clusters is not None:
+ result['cluster'] = self.cluster_weight if self.cluster_weight is not None else self._unit_weight('cluster')
+ if self.periods is not None:
+ result['period'] = self.period_weights if self.period_weights is not None else self._unit_weight('period')
+ if self.scenarios is not None:
+ result['scenario'] = (
+ self.scenario_weights if self.scenario_weights is not None else self._unit_weight('scenario')
+ )
+ return result
+
+ def sum_temporal(self, data: xr.DataArray) -> xr.DataArray:
+ """Sum data over temporal dimensions with full temporal weighting.
+
+ Applies both timestep_duration and cluster_weight, then sums over temporal dimensions.
+ Use this to convert rates to totals (e.g., flow_rate β total_energy).
+
+ Args:
+ data: Data with time dimension (and optionally cluster).
+ Typically a rate (e.g., flow_rate in MW, status as 0/1).
+
+ Returns:
+ Data summed over temporal dims with full temporal weighting applied.
+
+ Example:
+ >>> total_energy = fs.sum_temporal(flow_rate) # MW β MWh total
+ >>> active_hours = fs.sum_temporal(status) # count β hours
+ """
+ return (data * self.temporal_weight).sum(self.temporal_dims)
+
+ @property
+ def is_clustered(self) -> bool:
+ """Check if this FlowSystem uses time series clustering.
+
+ Returns:
+ True if the FlowSystem was created with transform.cluster(),
+ False otherwise.
+
+ Example:
+ >>> fs_clustered = flow_system.transform.cluster(n_clusters=8, cluster_duration='1D')
+ >>> fs_clustered.is_clustered
+ True
+ >>> flow_system.is_clustered
+ False
+ """
+ return getattr(self, 'clustering', None) is not None
def _validate_scenario_parameter(self, value: bool | list[str], param_name: str, element_type: str) -> None:
"""
diff --git a/flixopt/io.py b/flixopt/io.py
index 288d35db8..164a9fb2e 100644
--- a/flixopt/io.py
+++ b/flixopt/io.py
@@ -7,6 +7,7 @@
import pathlib
import re
import sys
+import warnings
from contextlib import contextmanager
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any
@@ -559,13 +560,16 @@ def save_dataset_to_netcdf(
if hasattr(coord_var, 'attrs') and coord_var.attrs:
ds[coord_name].attrs = {'attrs': json.dumps(coord_var.attrs)}
- ds.to_netcdf(
- path,
- encoding=None
- if compression == 0
- else {data_var: {'zlib': True, 'complevel': compression} for data_var in ds.data_vars},
- engine='netcdf4',
- )
+ # Suppress numpy binary compatibility warnings from netCDF4 (numpy 1->2 transition)
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', category=RuntimeWarning, message='numpy.ndarray size changed')
+ ds.to_netcdf(
+ path,
+ encoding=None
+ if compression == 0
+ else {data_var: {'zlib': True, 'complevel': compression} for data_var in ds.data_vars},
+ engine='netcdf4',
+ )
def load_dataset_from_netcdf(path: str | pathlib.Path) -> xr.Dataset:
@@ -578,7 +582,10 @@ def load_dataset_from_netcdf(path: str | pathlib.Path) -> xr.Dataset:
Returns:
Dataset: Loaded dataset with restored attrs.
"""
- ds = xr.load_dataset(str(path), engine='netcdf4')
+ # Suppress numpy binary compatibility warnings from netCDF4 (numpy 1->2 transition)
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', category=RuntimeWarning, message='numpy.ndarray size changed')
+ ds = xr.load_dataset(str(path), engine='netcdf4')
# Restore Dataset attrs
if 'attrs' in ds.attrs:
diff --git a/flixopt/optimization.py b/flixopt/optimization.py
index b76ceaf03..0b567387f 100644
--- a/flixopt/optimization.py
+++ b/flixopt/optimization.py
@@ -1,11 +1,12 @@
"""
This module contains the Optimization functionality for the flixopt framework.
It is used to optimize a FlowSystemModel for a given FlowSystem through a solver.
-There are three different Optimization types:
+
+There are two Optimization types:
1. Optimization: Optimizes the FlowSystemModel for the full FlowSystem
- 2. ClusteredOptimization: Optimizes the FlowSystemModel for the full FlowSystem, but clusters the TimeSeriesData.
- This simplifies the mathematical model and usually speeds up the solving process.
- 3. SegmentedOptimization: Solves a FlowSystemModel for each individual Segment of the FlowSystem.
+ 2. SegmentedOptimization: Solves a FlowSystemModel for each individual Segment of the FlowSystem.
+
+For time series aggregation (clustering), use FlowSystem.transform.cluster() instead.
"""
from __future__ import annotations
@@ -16,27 +17,22 @@
import sys
import timeit
import warnings
-from collections import Counter
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
-import numpy as np
from tqdm import tqdm
from . import io as fx_io
-from .clustering import Clustering, ClusteringModel, ClusteringParameters
from .components import Storage
from .config import CONFIG, DEPRECATION_REMOVAL_VERSION, SUCCESS_LEVEL
-from .core import DataConverter, TimeSeriesData, drop_constant_arrays
from .effects import PENALTY_EFFECT_LABEL
from .features import InvestmentModel
-from .flow_system import FlowSystem
from .results import Results, SegmentedResults
if TYPE_CHECKING:
import pandas as pd
import xarray as xr
- from .elements import Component
+ from .flow_system import FlowSystem
from .solvers import _Solver
from .structure import FlowSystemModel
@@ -86,7 +82,7 @@ def _initialize_optimization_common(
name: str,
flow_system: FlowSystem,
folder: pathlib.Path | None = None,
- normalize_weights: bool = True,
+ normalize_weights: bool | None = None,
) -> None:
"""
Shared initialization logic for all optimization types.
@@ -99,7 +95,7 @@ def _initialize_optimization_common(
name: Name of the optimization
flow_system: FlowSystem to optimize
folder: Directory for saving results
- normalize_weights: Whether to normalize scenario weights
+ normalize_weights: Deprecated. Scenario weights are now always normalized in FlowSystem.
"""
obj.name = name
@@ -110,7 +106,8 @@ def _initialize_optimization_common(
)
flow_system = flow_system.copy()
- obj.normalize_weights = normalize_weights
+ # normalize_weights is deprecated but kept for backwards compatibility
+ obj.normalize_weights = True # Always True now
flow_system._used_in_optimization = True
@@ -190,7 +187,7 @@ def do_modeling(self) -> Optimization:
t_start = timeit.default_timer()
self.flow_system.connect_and_transform()
- self.model = self.flow_system.create_model(self.normalize_weights)
+ self.model = self.flow_system.create_model()
self.model.do_modeling()
self.durations['modeling'] = round(timeit.default_timer() - t_start, 2)
@@ -357,162 +354,6 @@ def modeled(self) -> bool:
return True if self.model is not None else False
-class ClusteredOptimization(Optimization):
- """
- ClusteredOptimization reduces computational complexity by clustering time series into typical periods.
-
- This optimization approach clusters time series data using techniques from the tsam library to identify
- representative time periods, significantly reducing computation time while maintaining solution accuracy.
-
- Note:
- The quality of the solution depends on the choice of aggregation parameters.
- The optimal parameters depend on the specific problem and the characteristics of the time series data.
- For more information, refer to the [tsam documentation](https://tsam.readthedocs.io/en/latest/).
-
- Args:
- name: Name of the optimization
- flow_system: FlowSystem to be optimized
- clustering_parameters: Parameters for clustering. See ClusteringParameters class documentation
- components_to_clusterize: list of Components to perform aggregation on. If None, all components are aggregated.
- This equalizes variables in the components according to the typical periods computed in the aggregation
- folder: Folder where results should be saved. If None, current working directory is used
- normalize_weights: Whether to automatically normalize the weights of scenarios to sum up to 1 when solving
-
- Attributes:
- clustering (Clustering | None): Contains the clustered time series data
- clustering_model (ClusteringModel | None): Contains Variables and Constraints that equalize clusters of the time series data
- """
-
- def __init__(
- self,
- name: str,
- flow_system: FlowSystem,
- clustering_parameters: ClusteringParameters,
- components_to_clusterize: list[Component] | None = None,
- folder: pathlib.Path | None = None,
- normalize_weights: bool = True,
- ):
- warnings.warn(
- f'ClusteredOptimization is deprecated and will be removed in v{DEPRECATION_REMOVAL_VERSION}. '
- 'Use FlowSystem.transform.cluster(params) followed by FlowSystem.optimize(solver) instead. '
- 'Example: clustered_fs = flow_system.transform.cluster(params); clustered_fs.optimize(solver)',
- DeprecationWarning,
- stacklevel=2,
- )
- if flow_system.scenarios is not None:
- raise ValueError('Clustering is not supported for scenarios yet. Please use Optimization instead.')
- if flow_system.periods is not None:
- raise ValueError('Clustering is not supported for periods yet. Please use Optimization instead.')
- # Skip parent deprecation warning by calling common init directly
- _initialize_optimization_common(
- self,
- name=name,
- flow_system=flow_system,
- folder=folder,
- normalize_weights=normalize_weights,
- )
- self.clustering_parameters = clustering_parameters
- self.components_to_clusterize = components_to_clusterize
- self.clustering: Clustering | None = None
- self.clustering_model: ClusteringModel | None = None
-
- def do_modeling(self) -> ClusteredOptimization:
- t_start = timeit.default_timer()
- self.flow_system.connect_and_transform()
- self._perform_clustering()
-
- # Model the System
- self.model = self.flow_system.create_model(self.normalize_weights)
- self.model.do_modeling()
- # Add Clustering Submodel after modeling the rest
- self.clustering_model = ClusteringModel(
- self.model, self.clustering_parameters, self.flow_system, self.clustering, self.components_to_clusterize
- )
- self.clustering_model.do_modeling()
- self.durations['modeling'] = round(timeit.default_timer() - t_start, 2)
- return self
-
- def _perform_clustering(self):
- from .clustering import Clustering
-
- t_start_agg = timeit.default_timer()
-
- # Validation
- dt_min = float(self.flow_system.hours_per_timestep.min().item())
- dt_max = float(self.flow_system.hours_per_timestep.max().item())
- if not dt_min == dt_max:
- raise ValueError(
- f'Clustering failed due to inconsistent time step sizes:delta_t varies from {dt_min} to {dt_max} hours.'
- )
- ratio = self.clustering_parameters.hours_per_period / dt_max
- if not np.isclose(ratio, round(ratio), atol=1e-9):
- raise ValueError(
- f'The selected {self.clustering_parameters.hours_per_period=} does not match the time '
- f'step size of {dt_max} hours. It must be an integer multiple of {dt_max} hours.'
- )
-
- logger.info(f'{"":#^80}')
- logger.info(f'{" Clustering TimeSeries Data ":#^80}')
-
- ds = self.flow_system.to_dataset()
-
- temporaly_changing_ds = drop_constant_arrays(ds, dim='time')
-
- # Clustering - creation of clustered timeseries:
- self.clustering = Clustering(
- original_data=temporaly_changing_ds.to_dataframe(),
- hours_per_time_step=float(dt_min),
- hours_per_period=self.clustering_parameters.hours_per_period,
- nr_of_periods=self.clustering_parameters.nr_of_periods,
- weights=self.calculate_clustering_weights(temporaly_changing_ds),
- time_series_for_high_peaks=self.clustering_parameters.labels_for_high_peaks,
- time_series_for_low_peaks=self.clustering_parameters.labels_for_low_peaks,
- )
-
- self.clustering.cluster()
- result = self.clustering.plot(show=CONFIG.Plotting.default_show)
- result.to_html(self.folder / 'clustering.html')
- if self.clustering_parameters.aggregate_data_and_fix_non_binary_vars:
- ds = self.flow_system.to_dataset()
- for name, series in self.clustering.aggregated_data.items():
- da = (
- DataConverter.to_dataarray(series, self.flow_system.coords)
- .rename(name)
- .assign_attrs(ds[name].attrs)
- )
- if TimeSeriesData.is_timeseries_data(da):
- da = TimeSeriesData.from_dataarray(da)
-
- ds[name] = da
-
- self.flow_system = FlowSystem.from_dataset(ds)
- self.flow_system.connect_and_transform()
- self.durations['clustering'] = round(timeit.default_timer() - t_start_agg, 2)
-
- @classmethod
- def calculate_clustering_weights(cls, ds: xr.Dataset) -> dict[str, float]:
- """Calculate weights for all datavars in the dataset. Weights are pulled from the attrs of the datavars."""
- groups = [da.attrs.get('clustering_group') for da in ds.data_vars.values() if 'clustering_group' in da.attrs]
- group_counts = Counter(groups)
-
- # Calculate weight for each group (1/count)
- group_weights = {group: 1 / count for group, count in group_counts.items()}
-
- weights = {}
- for name, da in ds.data_vars.items():
- clustering_group = da.attrs.get('clustering_group')
- group_weight = group_weights.get(clustering_group)
- if group_weight is not None:
- weights[name] = group_weight
- else:
- weights[name] = da.attrs.get('clustering_weight', 1)
-
- if np.all(np.isclose(list(weights.values()), 1, atol=1e-6)):
- logger.info('All Clustering weights were set to 1')
-
- return weights
-
-
class SegmentedOptimization:
"""Solve large optimization problems by dividing time horizon into (overlapping) segments.
diff --git a/flixopt/optimize_accessor.py b/flixopt/optimize_accessor.py
index f88cdf982..7aee930a4 100644
--- a/flixopt/optimize_accessor.py
+++ b/flixopt/optimize_accessor.py
@@ -53,7 +53,7 @@ def __init__(self, flow_system: FlowSystem) -> None:
"""
self._fs = flow_system
- def __call__(self, solver: _Solver, normalize_weights: bool = True) -> FlowSystem:
+ def __call__(self, solver: _Solver, normalize_weights: bool | None = None) -> FlowSystem:
"""
Build and solve the optimization model in one step.
@@ -64,7 +64,7 @@ def __call__(self, solver: _Solver, normalize_weights: bool = True) -> FlowSyste
Args:
solver: The solver to use (e.g., HighsSolver, GurobiSolver).
- normalize_weights: Whether to normalize scenario/period weights to sum to 1.
+ normalize_weights: Deprecated. Scenario weights are now always normalized in FlowSystem.
Returns:
The FlowSystem, for method chaining.
@@ -85,7 +85,18 @@ def __call__(self, solver: _Solver, normalize_weights: bool = True) -> FlowSyste
>>> solution = flow_system.optimize(solver).solution
"""
- self._fs.build_model(normalize_weights)
+ if normalize_weights is not None:
+ import warnings
+
+ from .config import DEPRECATION_REMOVAL_VERSION
+
+ warnings.warn(
+ f'\n\nnormalize_weights parameter is deprecated and will be removed in {DEPRECATION_REMOVAL_VERSION}. '
+ 'Scenario weights are now always normalized when set on FlowSystem.\n',
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ self._fs.build_model()
self._fs.solve(solver)
return self._fs
diff --git a/flixopt/plot_result.py b/flixopt/plot_result.py
index 683fbcf3e..85e692602 100644
--- a/flixopt/plot_result.py
+++ b/flixopt/plot_result.py
@@ -41,7 +41,7 @@ class PlotResult:
Customizing the figure:
- >>> result = clustering.plot()
+ >>> result = clustering.plot.compare()
>>> result.update(title='My Custom Title').show()
"""
diff --git a/flixopt/results.py b/flixopt/results.py
index 16d88743a..8ec860244 100644
--- a/flixopt/results.py
+++ b/flixopt/results.py
@@ -99,7 +99,7 @@ class Results(CompositeContainerMixin['ComponentResults | BusResults | EffectRes
buses: Dictionary mapping bus labels to BusResults objects
effects: Dictionary mapping effect names to EffectResults objects
timesteps_extra: Extended time index including boundary conditions
- hours_per_timestep: Duration of each timestep for proper energy optimizations
+ timestep_duration: Duration of each timestep in hours for proper energy calculations
Examples:
Load and analyze saved results:
@@ -285,7 +285,7 @@ def __init__(
self.flows = ResultsContainer(elements=flows_dict, element_type_name='flow results', truncate_repr=10)
self.timesteps_extra = self.solution.indexes['time']
- self.hours_per_timestep = FlowSystem.calculate_hours_per_timestep(self.timesteps_extra)
+ self.timestep_duration = FlowSystem.calculate_timestep_duration(self.timesteps_extra)
self.scenarios = self.solution.indexes['scenario'] if 'scenario' in self.solution.indexes else None
self.periods = self.solution.indexes['period'] if 'period' in self.solution.indexes else None
@@ -623,7 +623,7 @@ def flow_hours(
.. deprecated::
Use `results.plot.all_flow_hours` (Dataset) or
- `results.flows['FlowLabel'].flow_rate * results.hours_per_timestep` instead.
+ `results.flows['FlowLabel'].flow_rate * results.timestep_duration` instead.
**Note**: The new API differs from this method:
@@ -675,7 +675,7 @@ def flow_hours(
stacklevel=2,
)
if self._flow_hours is None:
- self._flow_hours = (self.flow_rates() * self.hours_per_timestep).rename('flow_hours')
+ self._flow_hours = (self.flow_rates() * self.timestep_duration).rename('flow_hours')
filters = {k: v for k, v in {'start': start, 'end': end, 'component': component}.items() if v is not None}
return filter_dataarray_by_coord(self._flow_hours, **filters)
@@ -1577,14 +1577,14 @@ def plot_node_balance_pie(
dpi = plot_kwargs.pop('dpi', None) # None uses CONFIG.Plotting.default_dpi
inputs = sanitize_dataset(
- ds=self.solution[self.inputs] * self._results.hours_per_timestep,
+ ds=self.solution[self.inputs] * self._results.timestep_duration,
threshold=1e-5,
drop_small_vars=True,
zero_small_values=True,
drop_suffix='|',
)
outputs = sanitize_dataset(
- ds=self.solution[self.outputs] * self._results.hours_per_timestep,
+ ds=self.solution[self.outputs] * self._results.timestep_duration,
threshold=1e-5,
drop_small_vars=True,
zero_small_values=True,
@@ -1715,7 +1715,7 @@ def node_balance(
ds, _ = _apply_selection_to_data(ds, select=select, drop=True)
if unit_type == 'flow_hours':
- ds = ds * self._results.hours_per_timestep
+ ds = ds * self._results.timestep_duration
ds = ds.rename_vars({var: var.replace('flow_rate', 'flow_hours') for var in ds.data_vars})
return ds
@@ -2016,7 +2016,7 @@ def flow_rate(self) -> xr.DataArray:
@property
def flow_hours(self) -> xr.DataArray:
- return (self.flow_rate * self._results.hours_per_timestep).rename(f'{self.label}|flow_hours')
+ return (self.flow_rate * self._results.timestep_duration).rename(f'{self.label}|flow_hours')
@property
def size(self) -> xr.DataArray:
diff --git a/flixopt/statistics_accessor.py b/flixopt/statistics_accessor.py
index 952047cc5..536c6beaf 100644
--- a/flixopt/statistics_accessor.py
+++ b/flixopt/statistics_accessor.py
@@ -25,7 +25,6 @@
import numpy as np
import pandas as pd
-import plotly.express as px
import plotly.graph_objects as go
import xarray as xr
@@ -124,55 +123,51 @@ def _reshape_time_for_heatmap(
return result.transpose('timestep', 'timeframe', *other_dims)
-def _heatmap_figure(
- data: xr.DataArray,
- colors: str | list[str] | None = None,
- title: str = '',
- facet_col: str | None = None,
- animation_frame: str | None = None,
- facet_col_wrap: int | None = None,
- **imshow_kwargs: Any,
-) -> go.Figure:
- """Create heatmap figure using px.imshow.
+# --- Helper functions ---
- Args:
- data: DataArray with 2-4 dimensions. First two are heatmap axes.
- colors: Colorscale name (str) or list of colors. Dicts are not supported
- for heatmaps as color_continuous_scale requires a colorscale specification.
- title: Plot title.
- facet_col: Dimension for subplot columns.
- animation_frame: Dimension for animation slider.
- facet_col_wrap: Max columns before wrapping.
- **imshow_kwargs: Additional args for px.imshow.
- Returns:
- Plotly Figure.
- """
- if data.size == 0:
- return go.Figure()
+def _prepare_for_heatmap(
+ da: xr.DataArray,
+ reshape: tuple[str, str] | Literal['auto'] | None,
+ facet_col: str | Literal['auto'] | None,
+ animation_frame: str | Literal['auto'] | None,
+) -> xr.DataArray:
+ """Prepare DataArray for heatmap: determine axes, reshape if needed, transpose/squeeze."""
- colors = colors or CONFIG.Plotting.default_sequential_colorscale
- facet_col_wrap = facet_col_wrap or CONFIG.Plotting.default_facet_cols
+ def finalize(da: xr.DataArray, heatmap_dims: list[str]) -> xr.DataArray:
+ """Transpose, squeeze, and clear name if needed."""
+ other = [d for d in da.dims if d not in heatmap_dims]
+ da = da.transpose(*[d for d in heatmap_dims if d in da.dims], *other)
+ for dim in [d for d in da.dims if d not in heatmap_dims and da.sizes[d] == 1]:
+ da = da.squeeze(dim, drop=True)
+ return da.rename('') if da.sizes.get('variable', 1) > 1 else da
- imshow_args: dict[str, Any] = {
- 'img': data,
- 'color_continuous_scale': colors,
- 'title': title,
- **imshow_kwargs,
- }
+ def fallback_dims() -> list[str]:
+ """Default dims: (variable, time) if multi-var, else first 2 dims with size > 1."""
+ if da.sizes.get('variable', 1) > 1:
+ return ['variable', 'time']
+ dims = [d for d in da.dims if da.sizes[d] > 1][:2]
+ return dims if len(dims) >= 2 else list(da.dims)[:2]
- if facet_col and facet_col in data.dims:
- imshow_args['facet_col'] = facet_col
- if facet_col_wrap < data.sizes[facet_col]:
- imshow_args['facet_col_wrap'] = facet_col_wrap
+ is_clustered = 'cluster' in da.dims and da.sizes['cluster'] > 1
+ has_time = 'time' in da.dims
- if animation_frame and animation_frame in data.dims:
- imshow_args['animation_frame'] = animation_frame
+ # Clustered: use (time, cluster) as natural 2D
+ if is_clustered and reshape in ('auto', None):
+ return finalize(da, ['time', 'cluster'])
- return px.imshow(**imshow_args)
+ # Explicit reshape: always apply
+ if reshape and reshape != 'auto' and has_time:
+ return finalize(_reshape_time_for_heatmap(da, reshape), ['timestep', 'timeframe'])
+ # Auto reshape (non-clustered): apply only if extra dims fit in available slots
+ if reshape == 'auto' and has_time:
+ extra = [d for d in da.dims if d not in ('time', 'variable') and da.sizes[d] > 1]
+ slots = (facet_col == 'auto') + (animation_frame == 'auto')
+ if len(extra) <= slots:
+ return finalize(_reshape_time_for_heatmap(da, ('D', 'h')), ['timestep', 'timeframe'])
-# --- Helper functions ---
+ return finalize(da, fallback_dims())
def _filter_by_pattern(
@@ -228,17 +223,6 @@ def _filter_by_carrier(ds: xr.Dataset, carrier: str | list[str] | None) -> xr.Da
return ds[matching_vars] if matching_vars else xr.Dataset()
-def _resolve_facets(
- ds: xr.Dataset,
- facet_col: str | None,
- facet_row: str | None,
-) -> tuple[str | None, str | None]:
- """Resolve facet dimensions, returning None if not present in data."""
- actual_facet_col = facet_col if facet_col and facet_col in ds.dims else None
- actual_facet_row = facet_row if facet_row and facet_row in ds.dims else None
- return actual_facet_col, actual_facet_row
-
-
def _dataset_to_long_df(ds: xr.Dataset, value_name: str = 'value', var_name: str = 'variable') -> pd.DataFrame:
"""Convert xarray Dataset to long-form DataFrame for plotly express."""
if not ds.data_vars:
@@ -252,65 +236,6 @@ def _dataset_to_long_df(ds: xr.Dataset, value_name: str = 'value', var_name: str
return df.melt(id_vars=coord_cols, var_name=var_name, value_name=value_name)
-def _create_stacked_bar(
- ds: xr.Dataset,
- colors: ColorType,
- title: str,
- facet_col: str | None,
- facet_row: str | None,
- **plotly_kwargs: Any,
-) -> go.Figure:
- """Create a stacked bar chart from xarray Dataset."""
- df = _dataset_to_long_df(ds)
- if df.empty:
- return go.Figure()
- x_col = 'time' if 'time' in df.columns else df.columns[0]
- variables = df['variable'].unique().tolist()
- color_map = process_colors(colors, variables, default_colorscale=CONFIG.Plotting.default_qualitative_colorscale)
- fig = px.bar(
- df,
- x=x_col,
- y='value',
- color='variable',
- facet_col=facet_col,
- facet_row=facet_row,
- color_discrete_map=color_map,
- title=title,
- **plotly_kwargs,
- )
- fig.update_layout(barmode='relative', bargap=0, bargroupgap=0)
- fig.update_traces(marker_line_width=0)
- return fig
-
-
-def _create_line(
- ds: xr.Dataset,
- colors: ColorType,
- title: str,
- facet_col: str | None,
- facet_row: str | None,
- **plotly_kwargs: Any,
-) -> go.Figure:
- """Create a line chart from xarray Dataset."""
- df = _dataset_to_long_df(ds)
- if df.empty:
- return go.Figure()
- x_col = 'time' if 'time' in df.columns else df.columns[0]
- variables = df['variable'].unique().tolist()
- color_map = process_colors(colors, variables, default_colorscale=CONFIG.Plotting.default_qualitative_colorscale)
- return px.line(
- df,
- x=x_col,
- y='value',
- color='variable',
- facet_col=facet_col,
- facet_row=facet_row,
- color_discrete_map=color_map,
- title=title,
- **plotly_kwargs,
- )
-
-
# --- Statistics Accessor (data only) ---
@@ -471,7 +396,7 @@ def flow_hours(self) -> xr.Dataset:
"""
self._require_solution()
if self._flow_hours is None:
- hours = self._fs.hours_per_timestep
+ hours = self._fs.timestep_duration
flow_rates = self.flow_rates
# Multiply and preserve/transform attributes
data_vars = {}
@@ -784,9 +709,12 @@ def get_contributor_type(contributor: str) -> str:
label = f'{contributor}->{source_effect}({current_mode})'
if label in solution:
da = solution[label] * factor
- # For total mode, sum temporal over time
+ # For total mode, sum temporal over time (apply cluster_weight for proper weighting)
+ # Sum over all temporal dimensions (time, and cluster if present)
if mode == 'total' and current_mode == 'temporal' and 'time' in da.dims:
- da = da.sum('time')
+ weighted = da * self._fs.weights.get('cluster', 1.0)
+ temporal_dims = [d for d in weighted.dims if d not in ('period', 'scenario')]
+ da = weighted.sum(temporal_dims)
if share_total is None:
share_total = da
else:
@@ -1374,8 +1302,9 @@ def balance(
exclude: FilterType | None = None,
unit: Literal['flow_rate', 'flow_hours'] = 'flow_rate',
colors: ColorType | None = None,
- facet_col: str | None = 'period',
- facet_row: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
@@ -1388,8 +1317,11 @@ def balance(
exclude: Exclude flows containing these substrings.
unit: 'flow_rate' (power) or 'flow_hours' (energy).
colors: Color specification (colorscale name, color list, or label-to-color dict).
- facet_col: Dimension for column facets.
- facet_row: Dimension for row facets.
+ facet_col: Dimension for column facets. 'auto' uses first available of
+ cluster/period/scenario. None disables.
+ facet_row: Dimension for row facets. 'auto' uses first available after facet_col.
+ animation_frame: Dimension for animation slider. 'auto' uses first available
+ after facets.
show: Whether to display the plot.
Returns:
@@ -1426,7 +1358,6 @@ def balance(
ds[label] = -ds[label]
ds = _apply_selection(ds, select)
- actual_facet_col, actual_facet_row = _resolve_facets(ds, facet_col, facet_row)
# Build color map from Element.color attributes if no colors specified
if colors is None:
@@ -1438,12 +1369,12 @@ def balance(
first_var = next(iter(ds.data_vars))
unit_label = ds[first_var].attrs.get('unit', '')
- fig = _create_stacked_bar(
- ds,
+ fig = ds.fxplot.stacked_bar(
colors=colors,
title=f'{node} [{unit_label}]' if unit_label else node,
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
**plotly_kwargs,
)
@@ -1463,8 +1394,9 @@ def carrier_balance(
exclude: FilterType | None = None,
unit: Literal['flow_rate', 'flow_hours'] = 'flow_rate',
colors: ColorType | None = None,
- facet_col: str | None = 'period',
- facet_row: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
@@ -1480,8 +1412,10 @@ def carrier_balance(
exclude: Exclude flows containing these substrings.
unit: 'flow_rate' (power) or 'flow_hours' (energy).
colors: Color specification (colorscale name, color list, or label-to-color dict).
- facet_col: Dimension for column facets.
- facet_row: Dimension for row facets.
+ facet_col: Dimension for column facets. 'auto' uses first available of
+ cluster/period/scenario.
+ facet_row: Dimension for row facets. 'auto' uses first available after facet_col.
+ animation_frame: Dimension for animation slider.
show: Whether to display the plot.
Returns:
@@ -1532,7 +1466,6 @@ def carrier_balance(
ds[label] = -ds[label]
ds = _apply_selection(ds, select)
- actual_facet_col, actual_facet_row = _resolve_facets(ds, facet_col, facet_row)
# Use cached component colors for flows
if colors is None:
@@ -1557,12 +1490,12 @@ def carrier_balance(
first_var = next(iter(ds.data_vars))
unit_label = ds[first_var].attrs.get('unit', '')
- fig = _create_stacked_bar(
- ds,
+ fig = ds.fxplot.stacked_bar(
colors=colors,
title=f'{carrier.capitalize()} Balance [{unit_label}]' if unit_label else f'{carrier.capitalize()} Balance',
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
**plotly_kwargs,
)
@@ -1578,18 +1511,20 @@ def heatmap(
variables: str | list[str],
*,
select: SelectType | None = None,
- reshape: tuple[str, str] | None = ('D', 'h'),
+ reshape: tuple[str, str] | Literal['auto'] | None = 'auto',
colors: str | list[str] | None = None,
- facet_col: str | None = 'period',
- animation_frame: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
"""Plot heatmap of time series data.
- Time is reshaped into 2D (e.g., days Γ hours) when possible. Multiple variables
- are shown as facets. If too many dimensions exist to display without data loss,
- reshaping is skipped and variables are shown on the y-axis with time on x-axis.
+ Time is reshaped into 2D (e.g., days Γ hours) when possible. For clustered data,
+ the natural (cluster, time) shape is used directly without reshaping.
+
+ Multiple variables are shown as facets. If too many dimensions exist to display
+ without data loss, reshaping is skipped and variables are shown on the y-axis.
Args:
variables: Flow label(s) or variable name(s). Flow labels like 'Boiler(Q_th)'
@@ -1597,12 +1532,13 @@ def heatmap(
names like 'Storage|charge_state' are used as-is.
select: xarray-style selection, e.g. {'scenario': 'Base Case'}.
reshape: Time reshape frequencies as (outer, inner), e.g. ('D', 'h') for
- days Γ hours. Set to None to disable reshaping.
+ days Γ hours. 'auto' uses (cluster, time) for clustered data or
+ ('D', 'h') otherwise. None disables reshaping.
colors: Colorscale name (str) or list of colors for heatmap coloring.
Dicts are not supported for heatmaps (use str or list[str]).
- facet_col: Dimension for subplot columns (default: 'period').
- With multiple variables, 'variable' is used instead.
- animation_frame: Dimension for animation slider (default: 'scenario').
+ facet_col: Dimension for subplot columns. 'auto' uses first available of
+ cluster/period/scenario. With multiple variables, 'variable' is used.
+ animation_frame: Dimension for animation slider. 'auto' uses first available.
show: Whether to display the figure.
**plotly_kwargs: Additional arguments passed to px.imshow.
@@ -1610,85 +1546,25 @@ def heatmap(
PlotResult with processed data and figure.
"""
solution = self._stats._require_solution()
-
if isinstance(variables, str):
variables = [variables]
- # Resolve flow labels to variable names
- resolved_variables = self._resolve_variable_names(variables, solution)
-
- ds = solution[resolved_variables]
- ds = _apply_selection(ds, select)
+ # Resolve, select, and stack into single DataArray
+ resolved = self._resolve_variable_names(variables, solution)
+ ds = _apply_selection(solution[resolved], select)
+ da = xr.concat([ds[v] for v in ds.data_vars], dim=pd.Index(list(ds.data_vars), name='variable'))
- # Stack variables into single DataArray
- variable_names = list(ds.data_vars)
- dataarrays = [ds[var] for var in variable_names]
- da = xr.concat(dataarrays, dim=pd.Index(variable_names, name='variable'))
+ # Prepare for heatmap (reshape, transpose, squeeze)
+ da = _prepare_for_heatmap(da, reshape, facet_col, animation_frame)
- # Determine facet and animation from available dims
- has_multiple_vars = 'variable' in da.dims and da.sizes['variable'] > 1
-
- if has_multiple_vars:
- actual_facet = 'variable'
- actual_animation = (
- animation_frame
- if animation_frame in da.dims
- else (facet_col if facet_col in da.dims and da.sizes.get(facet_col, 1) > 1 else None)
- )
- else:
- actual_facet = facet_col if facet_col in da.dims and da.sizes.get(facet_col, 0) > 1 else None
- actual_animation = (
- animation_frame if animation_frame in da.dims and da.sizes.get(animation_frame, 0) > 1 else None
- )
-
- # Count non-time dims with size > 1 (these need facet/animation slots)
- extra_dims = [d for d in da.dims if d != 'time' and da.sizes[d] > 1]
- used_slots = len([d for d in [actual_facet, actual_animation] if d])
- would_drop = len(extra_dims) > used_slots
-
- # Reshape time only if we wouldn't lose data (all extra dims fit in facet + animation)
- if reshape and 'time' in da.dims and not would_drop:
- da = _reshape_time_for_heatmap(da, reshape)
- heatmap_dims = ['timestep', 'timeframe']
- elif has_multiple_vars:
- # Can't reshape but have multiple vars: use variable + time as heatmap axes
- heatmap_dims = ['variable', 'time']
- # variable is now a heatmap dim, use period/scenario for facet/animation
- actual_facet = facet_col if facet_col in da.dims and da.sizes.get(facet_col, 0) > 1 else None
- actual_animation = (
- animation_frame if animation_frame in da.dims and da.sizes.get(animation_frame, 0) > 1 else None
- )
- else:
- heatmap_dims = ['time'] if 'time' in da.dims else list(da.dims)[:1]
-
- # Keep only dims we need
- keep_dims = set(heatmap_dims) | {d for d in [actual_facet, actual_animation] if d is not None}
- for dim in [d for d in da.dims if d not in keep_dims]:
- da = da.isel({dim: 0}, drop=True) if da.sizes[dim] > 1 else da.squeeze(dim, drop=True)
-
- # Transpose to expected order
- dim_order = heatmap_dims + [d for d in [actual_facet, actual_animation] if d]
- da = da.transpose(*dim_order)
-
- # Clear name for multiple variables (colorbar would show first var's name)
- if has_multiple_vars:
- da = da.rename('')
-
- fig = _heatmap_figure(
- da,
- colors=colors,
- facet_col=actual_facet,
- animation_frame=actual_animation,
- **plotly_kwargs,
- )
+ fig = da.fxplot.heatmap(colors=colors, facet_col=facet_col, animation_frame=animation_frame, **plotly_kwargs)
if show is None:
show = CONFIG.Plotting.default_show
if show:
fig.show()
- reshaped_ds = da.to_dataset(name='value') if isinstance(da, xr.DataArray) else da
- return PlotResult(data=reshaped_ds, figure=fig)
+ return PlotResult(data=da.to_dataset(name='value'), figure=fig)
def flows(
self,
@@ -1699,8 +1575,9 @@ def flows(
select: SelectType | None = None,
unit: Literal['flow_rate', 'flow_hours'] = 'flow_rate',
colors: ColorType | None = None,
- facet_col: str | None = 'period',
- facet_row: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
@@ -1713,8 +1590,9 @@ def flows(
select: xarray-style selection.
unit: 'flow_rate' or 'flow_hours'.
colors: Color specification (colorscale name, color list, or label-to-color dict).
- facet_col: Dimension for column facets.
+ facet_col: Dimension for column facets. 'auto' uses first available.
facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
show: Whether to display.
Returns:
@@ -1757,7 +1635,6 @@ def flows(
ds = ds[[lbl for lbl in matching_labels if lbl in ds]]
ds = _apply_selection(ds, select)
- actual_facet_col, actual_facet_row = _resolve_facets(ds, facet_col, facet_row)
# Get unit label from first data variable's attributes
unit_label = ''
@@ -1765,12 +1642,12 @@ def flows(
first_var = next(iter(ds.data_vars))
unit_label = ds[first_var].attrs.get('unit', '')
- fig = _create_line(
- ds,
+ fig = ds.fxplot.line(
colors=colors,
title=f'Flows [{unit_label}]' if unit_label else 'Flows',
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
**plotly_kwargs,
)
@@ -1787,8 +1664,9 @@ def sizes(
max_size: float | None = 1e6,
select: SelectType | None = None,
colors: ColorType | None = None,
- facet_col: str | None = 'period',
- facet_row: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
@@ -1798,8 +1676,9 @@ def sizes(
max_size: Maximum size to include (filters defaults).
select: xarray-style selection.
colors: Color specification (colorscale name, color list, or label-to-color dict).
- facet_col: Dimension for column facets.
+ facet_col: Dimension for column facets. 'auto' uses first available.
facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
show: Whether to display.
Returns:
@@ -1814,24 +1693,18 @@ def sizes(
valid_labels = [lbl for lbl in ds.data_vars if float(ds[lbl].max()) < max_size]
ds = ds[valid_labels]
- actual_facet_col, actual_facet_row = _resolve_facets(ds, facet_col, facet_row)
-
- df = _dataset_to_long_df(ds)
- if df.empty:
+ if not ds.data_vars:
fig = go.Figure()
else:
- variables = df['variable'].unique().tolist()
- color_map = process_colors(colors, variables)
- fig = px.bar(
- df,
+ fig = ds.fxplot.bar(
x='variable',
- y='value',
color='variable',
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
- color_discrete_map=color_map,
+ colors=colors,
title='Investment Sizes',
- labels={'variable': 'Flow', 'value': 'Size'},
+ ylabel='Size',
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
**plotly_kwargs,
)
@@ -1849,8 +1722,9 @@ def duration_curve(
select: SelectType | None = None,
normalize: bool = False,
colors: ColorType | None = None,
- facet_col: str | None = 'period',
- facet_row: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
@@ -1864,8 +1738,9 @@ def duration_curve(
select: xarray-style selection.
normalize: If True, normalize x-axis to 0-100%.
colors: Color specification (colorscale name, color list, or label-to-color dict).
- facet_col: Dimension for column facets.
+ facet_col: Dimension for column facets. 'auto' uses first available.
facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
show: Whether to display.
Returns:
@@ -1924,20 +1799,18 @@ def sort_descending(arr: np.ndarray) -> np.ndarray:
duration_coord = np.linspace(0, 100, n_timesteps) if normalize else np.arange(n_timesteps)
result_ds = result_ds.assign_coords({duration_name: duration_coord})
- actual_facet_col, actual_facet_row = _resolve_facets(result_ds, facet_col, facet_row)
-
# Get unit label from first data variable's attributes
unit_label = ''
if ds.data_vars:
first_var = next(iter(ds.data_vars))
unit_label = ds[first_var].attrs.get('unit', '')
- fig = _create_line(
- result_ds,
+ fig = result_ds.fxplot.line(
colors=colors,
title=f'Duration Curve [{unit_label}]' if unit_label else 'Duration Curve',
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
**plotly_kwargs,
)
@@ -1959,8 +1832,9 @@ def effects(
by: Literal['component', 'contributor', 'time'] | None = None,
select: SelectType | None = None,
colors: ColorType | None = None,
- facet_col: str | None = 'period',
- facet_row: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
@@ -1974,8 +1848,9 @@ def effects(
or None to show aggregated totals per effect.
select: xarray-style selection.
colors: Color specification (colorscale name, color list, or label-to-color dict).
- facet_col: Dimension for column facets (ignored if not in data).
- facet_row: Dimension for row facets (ignored if not in data).
+ facet_col: Dimension for column facets. 'auto' uses first available.
+ facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
show: Whether to display.
Returns:
@@ -1991,110 +1866,67 @@ def effects(
self._stats._require_solution()
# Get the appropriate effects dataset based on aspect
- if aspect == 'total':
- effects_ds = self._stats.total_effects
- elif aspect == 'temporal':
- effects_ds = self._stats.temporal_effects
- elif aspect == 'periodic':
- effects_ds = self._stats.periodic_effects
- else:
+ effects_ds = {
+ 'total': self._stats.total_effects,
+ 'temporal': self._stats.temporal_effects,
+ 'periodic': self._stats.periodic_effects,
+ }.get(aspect)
+ if effects_ds is None:
raise ValueError(f"Aspect '{aspect}' not valid. Choose from 'total', 'temporal', 'periodic'.")
- # Get available effects (data variables in the dataset)
- available_effects = list(effects_ds.data_vars)
-
- # Filter to specific effect if requested
+ # Filter to specific effect(s) and apply selection
if effect is not None:
- if effect not in available_effects:
- raise ValueError(f"Effect '{effect}' not found. Available: {available_effects}")
- effects_to_plot = [effect]
+ if effect not in effects_ds:
+ raise ValueError(f"Effect '{effect}' not found. Available: {list(effects_ds.data_vars)}")
+ ds = effects_ds[[effect]]
else:
- effects_to_plot = available_effects
-
- # Build a combined DataArray with effect dimension
- effect_arrays = []
- for eff in effects_to_plot:
- da = effects_ds[eff]
- if by == 'contributor':
- # Keep individual contributors (flows) - no groupby
- effect_arrays.append(da.expand_dims(effect=[eff]))
- else:
- # Group by component (sum over contributor within each component)
- da_grouped = da.groupby('component').sum()
- effect_arrays.append(da_grouped.expand_dims(effect=[eff]))
+ ds = effects_ds
- combined = xr.concat(effect_arrays, dim='effect')
+ # Group by component (default) unless by='contributor'
+ if by != 'contributor' and 'contributor' in ds.dims:
+ ds = ds.groupby('component').sum()
- # Apply selection
- combined = _apply_selection(combined.to_dataset(name='value'), select)['value']
+ ds = _apply_selection(ds, select)
- # Group by the specified dimension
+ # Sum over dimensions based on 'by' parameter
if by is None:
- # Aggregate totals per effect - sum over all dimensions except effect
- if 'time' in combined.dims:
- combined = combined.sum(dim='time')
- if 'component' in combined.dims:
- combined = combined.sum(dim='component')
- if 'contributor' in combined.dims:
- combined = combined.sum(dim='contributor')
- x_col = 'effect'
- color_col = 'effect'
+ for dim in ['time', 'component', 'contributor']:
+ if dim in ds.dims:
+ ds = ds.sum(dim=dim)
+ x_col, color_col = 'variable', 'variable'
elif by == 'component':
- # Sum over time if present
- if 'time' in combined.dims:
- combined = combined.sum(dim='time')
+ if 'time' in ds.dims:
+ ds = ds.sum(dim='time')
x_col = 'component'
- color_col = 'effect' if len(effects_to_plot) > 1 else 'component'
+ color_col = 'variable' if len(ds.data_vars) > 1 else 'component'
elif by == 'contributor':
- # Sum over time if present
- if 'time' in combined.dims:
- combined = combined.sum(dim='time')
+ if 'time' in ds.dims:
+ ds = ds.sum(dim='time')
x_col = 'contributor'
- color_col = 'effect' if len(effects_to_plot) > 1 else 'contributor'
+ color_col = 'variable' if len(ds.data_vars) > 1 else 'contributor'
elif by == 'time':
- if 'time' not in combined.dims:
+ if 'time' not in ds.dims:
raise ValueError(f"Cannot plot by 'time' for aspect '{aspect}' - no time dimension.")
- # Sum over components or contributors
- if 'component' in combined.dims:
- combined = combined.sum(dim='component')
- if 'contributor' in combined.dims:
- combined = combined.sum(dim='contributor')
+ for dim in ['component', 'contributor']:
+ if dim in ds.dims:
+ ds = ds.sum(dim=dim)
x_col = 'time'
- color_col = 'effect' if len(effects_to_plot) > 1 else None
+ color_col = 'variable' if len(ds.data_vars) > 1 else None
else:
raise ValueError(f"'by' must be one of 'component', 'contributor', 'time', or None, got {by!r}")
- # Resolve facets
- actual_facet_col, actual_facet_row = _resolve_facets(combined.to_dataset(name='value'), facet_col, facet_row)
+ # Build title
+ effect_label = effect or 'Effects'
+ title = f'{effect_label} ({aspect})' if by is None else f'{effect_label} ({aspect}) by {by}'
- # Convert to DataFrame for plotly express
- df = combined.to_dataframe(name='value').reset_index()
-
- # Build color map
- if color_col and color_col in df.columns:
- color_items = df[color_col].unique().tolist()
- color_map = process_colors(colors, color_items)
- else:
- color_map = None
-
- # Build title with unit if single effect
- effect_label = effect if effect else 'Effects'
- if effect and effect in effects_ds:
- unit_label = effects_ds[effect].attrs.get('unit', '')
- title = f'{effect_label} [{unit_label}]' if unit_label else effect_label
- else:
- title = effect_label
- title = f'{title} ({aspect})' if by is None else f'{title} ({aspect}) by {by}'
-
- fig = px.bar(
- df,
+ fig = ds.fxplot.bar(
x=x_col,
- y='value',
color=color_col,
- color_discrete_map=color_map,
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
+ colors=colors,
title=title,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
**plotly_kwargs,
)
fig.update_layout(bargap=0, bargroupgap=0)
@@ -2105,7 +1937,7 @@ def effects(
if show:
fig.show()
- return PlotResult(data=combined.to_dataset(name=aspect), figure=fig)
+ return PlotResult(data=ds, figure=fig)
def charge_states(
self,
@@ -2113,8 +1945,9 @@ def charge_states(
*,
select: SelectType | None = None,
colors: ColorType | None = None,
- facet_col: str | None = 'period',
- facet_row: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
@@ -2124,8 +1957,9 @@ def charge_states(
storages: Storage label(s) to plot. If None, plots all storages.
select: xarray-style selection.
colors: Color specification (colorscale name, color list, or label-to-color dict).
- facet_col: Dimension for column facets.
+ facet_col: Dimension for column facets. 'auto' uses first available.
facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
show: Whether to display.
Returns:
@@ -2140,14 +1974,13 @@ def charge_states(
ds = ds[[s for s in storages if s in ds]]
ds = _apply_selection(ds, select)
- actual_facet_col, actual_facet_row = _resolve_facets(ds, facet_col, facet_row)
- fig = _create_line(
- ds,
+ fig = ds.fxplot.line(
colors=colors,
title='Storage Charge States',
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
**plotly_kwargs,
)
fig.update_yaxes(title_text='Charge State')
@@ -2167,8 +2000,9 @@ def storage(
unit: Literal['flow_rate', 'flow_hours'] = 'flow_rate',
colors: ColorType | None = None,
charge_state_color: str = 'black',
- facet_col: str | None = 'period',
- facet_row: str | None = 'scenario',
+ facet_col: str | Literal['auto'] | None = 'auto',
+ facet_row: str | Literal['auto'] | None = 'auto',
+ animation_frame: str | Literal['auto'] | None = 'auto',
show: bool | None = None,
**plotly_kwargs: Any,
) -> PlotResult:
@@ -2184,8 +2018,9 @@ def storage(
unit: 'flow_rate' (power) or 'flow_hours' (energy).
colors: Color specification for flow bars.
charge_state_color: Color for the charge state line overlay.
- facet_col: Dimension for column facets.
+ facet_col: Dimension for column facets. 'auto' uses first available.
facet_row: Dimension for row facets.
+ animation_frame: Dimension for animation slider.
show: Whether to display.
Returns:
@@ -2229,62 +2064,68 @@ def storage(
# Apply selection
ds = _apply_selection(ds, select)
- actual_facet_col, actual_facet_row = _resolve_facets(ds, facet_col, facet_row)
- # Build color map
+ # Separate flow data from charge_state
flow_labels = [lbl for lbl in ds.data_vars if lbl != 'charge_state']
+ flow_ds = ds[flow_labels]
+ charge_da = ds['charge_state']
+
+ # Build color map for flows
if colors is None:
colors = self._get_color_map_for_balance(storage, flow_labels)
- color_map = process_colors(colors, flow_labels)
- color_map['charge_state'] = 'black'
-
- # Convert to long-form DataFrame
- df = _dataset_to_long_df(ds)
-
- # Create figure with facets using px.bar for flows, then add charge_state line
- flow_df = df[df['variable'] != 'charge_state']
- charge_df = df[df['variable'] == 'charge_state']
- fig = px.bar(
- flow_df,
+ # Create stacked bar chart for flows using fxplot
+ fig = flow_ds.fxplot.stacked_bar(
x='time',
- y='value',
color='variable',
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
- color_discrete_map=color_map,
+ colors=colors,
title=f'{storage} Operation ({unit})',
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
**plotly_kwargs,
)
- fig.update_layout(bargap=0, bargroupgap=0)
- fig.update_traces(marker_line_width=0)
- # Add charge state as line on secondary y-axis using px.line, then merge traces
- if not charge_df.empty:
- line_fig = px.line(
- charge_df,
+ # Add charge state as line on secondary y-axis
+ if charge_da.size > 0:
+ # Create line figure with same facets
+ line_fig = charge_da.fxplot.line(
x='time',
- y='value',
- facet_col=actual_facet_col,
- facet_row=actual_facet_row,
+ color=None, # Single line, no color grouping
+ facet_col=facet_col,
+ facet_row=facet_row,
+ animation_frame=animation_frame,
)
- # Update line traces and add to main figure
- for trace in line_fig.data:
- trace.name = 'charge_state'
- trace.line = dict(color=charge_state_color, width=2)
- trace.yaxis = 'y2'
- trace.showlegend = True
- fig.add_trace(trace)
- # Add secondary y-axis
- fig.update_layout(
- yaxis2=dict(
- title='Charge State',
- overlaying='y',
+ # Get the primary y-axes from the bar figure to create matching secondary axes
+ primary_yaxes = [key for key in fig.layout if key.startswith('yaxis')]
+
+ # For each primary y-axis, create a secondary y-axis
+ for i, primary_key in enumerate(sorted(primary_yaxes, key=lambda x: int(x[5:]) if x[5:] else 0)):
+ primary_num = primary_key[5:] if primary_key[5:] else '1'
+ secondary_num = int(primary_num) + 100
+ secondary_key = f'yaxis{secondary_num}'
+ secondary_anchor = f'x{primary_num}' if primary_num != '1' else 'x'
+
+ fig.layout[secondary_key] = dict(
+ overlaying=f'y{primary_num}' if primary_num != '1' else 'y',
side='right',
showgrid=False,
+ title='Charge State' if i == len(primary_yaxes) - 1 else None,
+ anchor=secondary_anchor,
)
- )
+
+ # Add line traces with correct axis assignments
+ for i, trace in enumerate(line_fig.data):
+ primary_num = i + 1 if i > 0 else 1
+ secondary_yaxis = f'y{primary_num + 100}'
+
+ trace.name = 'charge_state'
+ trace.line = dict(color=charge_state_color, width=2)
+ trace.yaxis = secondary_yaxis
+ trace.showlegend = i == 0
+ trace.legendgroup = 'charge_state'
+ fig.add_trace(trace)
if show is None:
show = CONFIG.Plotting.default_show
diff --git a/flixopt/structure.py b/flixopt/structure.py
index 88fd9ce31..4b7734199 100644
--- a/flixopt/structure.py
+++ b/flixopt/structure.py
@@ -10,6 +10,7 @@
import logging
import pathlib
import re
+import warnings
from dataclasses import dataclass
from difflib import get_close_matches
from typing import (
@@ -89,13 +90,11 @@ class FlowSystemModel(linopy.Model, SubmodelsMixin):
Args:
flow_system: The flow_system that is used to create the model.
- normalize_weights: Whether to automatically normalize the weights to sum up to 1 when solving.
"""
- def __init__(self, flow_system: FlowSystem, normalize_weights: bool):
+ def __init__(self, flow_system: FlowSystem):
super().__init__(force_dim_names=True)
self.flow_system = flow_system
- self.normalize_weights = normalize_weights
self.effects: EffectCollectionModel | None = None
self.submodels: Submodels = Submodels({})
@@ -169,7 +168,15 @@ def _add_scenario_equality_constraints(self):
@property
def solution(self):
"""Build solution dataset, reindexing to timesteps_extra for consistency."""
- solution = super().solution
+ # Suppress the linopy warning about coordinate mismatch.
+ # This warning is expected when storage charge_state has one more timestep than other variables.
+ with warnings.catch_warnings():
+ warnings.filterwarnings(
+ 'ignore',
+ category=UserWarning,
+ message='Coordinates across variables not equal',
+ )
+ solution = super().solution
solution['objective'] = self.objective.value
# Store attrs as JSON strings for netCDF compatibility
solution.attrs = {
@@ -204,48 +211,78 @@ def solution(self):
}
# Ensure solution is always indexed by timesteps_extra for consistency.
# Variables without extra timestep data will have NaN at the final timestep.
- if 'time' in solution.coords and not solution.indexes['time'].equals(self.flow_system.timesteps_extra):
- solution = solution.reindex(time=self.flow_system.timesteps_extra)
+ if 'time' in solution.coords:
+ if not solution.indexes['time'].equals(self.flow_system.timesteps_extra):
+ solution = solution.reindex(time=self.flow_system.timesteps_extra)
return solution
@property
- def hours_per_step(self):
- return self.flow_system.hours_per_timestep
+ def timestep_duration(self) -> xr.DataArray:
+ """Duration of each timestep in hours."""
+ return self.flow_system.timestep_duration
@property
def hours_of_previous_timesteps(self):
return self.flow_system.hours_of_previous_timesteps
+ @property
+ def dims(self) -> list[str]:
+ """Active dimension names."""
+ return self.flow_system.dims
+
+ @property
+ def indexes(self) -> dict[str, pd.Index]:
+ """Indexes for active dimensions."""
+ return self.flow_system.indexes
+
+ @property
+ def weights(self) -> dict[str, xr.DataArray]:
+ """Weights for active dimensions (unit weights if not set).
+
+ Scenario weights are always normalized (handled by FlowSystem).
+ """
+ return self.flow_system.weights
+
+ @property
+ def temporal_dims(self) -> list[str]:
+ """Temporal dimensions for summing over time.
+
+ Returns ['time', 'cluster'] for clustered systems, ['time'] otherwise.
+ """
+ return self.flow_system.temporal_dims
+
+ @property
+ def temporal_weight(self) -> xr.DataArray:
+ """Combined temporal weight (timestep_duration Γ cluster_weight)."""
+ return self.flow_system.temporal_weight
+
+ def sum_temporal(self, data: xr.DataArray) -> xr.DataArray:
+ """Sum data over temporal dimensions with full temporal weighting.
+
+ Example:
+ >>> total_energy = model.sum_temporal(flow_rate)
+ """
+ return self.flow_system.sum_temporal(data)
+
@property
def scenario_weights(self) -> xr.DataArray:
"""
- Scenario weights of model. With optional normalization.
+ Scenario weights of model (always normalized, via FlowSystem).
+
+ Returns unit weights if no scenarios defined or no explicit weights set.
"""
if self.flow_system.scenarios is None:
return xr.DataArray(1)
if self.flow_system.scenario_weights is None:
- scenario_weights = xr.DataArray(
- np.ones(self.flow_system.scenarios.size, dtype=float),
- coords={'scenario': self.flow_system.scenarios},
- dims=['scenario'],
- name='scenario_weights',
- )
- else:
- scenario_weights = self.flow_system.scenario_weights
-
- if not self.normalize_weights:
- return scenario_weights
+ return self.flow_system._unit_weight('scenario')
- norm = scenario_weights.sum('scenario')
- if np.isclose(norm, 0.0).any():
- raise ValueError('FlowSystemModel.scenario_weights: weights sum to 0; cannot normalize.')
- return scenario_weights / norm
+ return self.flow_system.scenario_weights
@property
def objective_weights(self) -> xr.DataArray:
"""
- Objective weights of model. With optional normalization of scenario weights.
+ Objective weights of model (period_weights Γ scenario_weights).
"""
period_weights = self.flow_system.effects.objective_effect.submodel.period_weights
scenario_weights = self.scenario_weights
@@ -262,7 +299,8 @@ def get_coords(
Args:
dims: The dimensions to include in the coordinates. If None, includes all dimensions
- extra_timestep: If True, uses extra timesteps instead of regular timesteps
+ extra_timestep: If True, uses extra timesteps instead of regular timesteps.
+ For clustered FlowSystems, extends time by 1 (for charge_state boundaries).
Returns:
The coordinates of the model, or None if no coordinates are available
@@ -276,7 +314,12 @@ def get_coords(
if dims is None:
coords = dict(self.flow_system.coords)
else:
- coords = {k: v for k, v in self.flow_system.coords.items() if k in dims}
+ # In clustered systems, 'time' is always paired with 'cluster'
+ # So when 'time' is requested, also include 'cluster' if available
+ effective_dims = set(dims)
+ if 'time' in dims and 'cluster' in self.flow_system.coords:
+ effective_dims.add('cluster')
+ coords = {k: v for k, v in self.flow_system.coords.items() if k in effective_dims}
if extra_timestep and coords:
coords['time'] = self.flow_system.timesteps_extra
@@ -1703,8 +1746,8 @@ def __repr__(self) -> str:
return f'{model_string}\n{"=" * len(model_string)}\n\n{all_sections}'
@property
- def hours_per_step(self):
- return self._model.hours_per_step
+ def timestep_duration(self):
+ return self._model.timestep_duration
def _do_modeling(self):
"""
diff --git a/flixopt/transform_accessor.py b/flixopt/transform_accessor.py
index eaec1a3b6..6a5b51caa 100644
--- a/flixopt/transform_accessor.py
+++ b/flixopt/transform_accessor.py
@@ -8,16 +8,15 @@
from __future__ import annotations
import logging
+import warnings
from collections import defaultdict
from typing import TYPE_CHECKING, Any, Literal
+import numpy as np
import pandas as pd
import xarray as xr
if TYPE_CHECKING:
- import numpy as np
-
- from .clustering import ClusteringParameters
from .flow_system import FlowSystem
logger = logging.getLogger('flixopt')
@@ -31,11 +30,11 @@ class TransformAccessor:
with modified structure or data, accessible via `flow_system.transform`.
Examples:
- Clustered optimization:
+ Time series aggregation (8 typical days):
- >>> clustered_fs = flow_system.transform.cluster(params)
- >>> clustered_fs.optimize(solver)
- >>> print(clustered_fs.solution)
+ >>> reduced_fs = flow_system.transform.cluster(n_clusters=8, cluster_duration='1D')
+ >>> reduced_fs.optimize(solver)
+ >>> expanded_fs = reduced_fs.transform.expand_solution()
Future MGA:
@@ -52,126 +51,6 @@ def __init__(self, flow_system: FlowSystem) -> None:
"""
self._fs = flow_system
- def cluster(
- self,
- parameters: ClusteringParameters,
- components_to_clusterize: list | None = None,
- ) -> FlowSystem:
- """
- Create a clustered FlowSystem for time series aggregation.
-
- This method creates a new FlowSystem that can be optimized with
- clustered time series data. The clustering reduces computational
- complexity by identifying representative time periods.
-
- The returned FlowSystem:
- - Has the same timesteps as the original (clustering works via constraints, not reduction)
- - Has aggregated time series data (if `aggregate_data_and_fix_non_binary_vars=True`)
- - Will have clustering constraints added during `build_model()`
-
- Args:
- parameters: Clustering parameters specifying period duration,
- number of periods, and aggregation settings.
- components_to_clusterize: List of components to apply clustering to.
- If None, all components are clustered.
-
- Returns:
- A new FlowSystem configured for clustered optimization.
-
- Raises:
- ValueError: If timestep sizes are inconsistent.
- ValueError: If hours_per_period is not a multiple of timestep size.
-
- Examples:
- Basic clustered optimization:
-
- >>> from flixopt import ClusteringParameters
- >>> params = ClusteringParameters(
- ... hours_per_period=24,
- ... nr_of_periods=8,
- ... fix_storage_flows=True,
- ... aggregate_data_and_fix_non_binary_vars=True,
- ... )
- >>> clustered_fs = flow_system.transform.cluster(params)
- >>> clustered_fs.optimize(solver)
- >>> print(clustered_fs.solution)
-
- With model modifications:
-
- >>> clustered_fs = flow_system.transform.cluster(params)
- >>> clustered_fs.build_model()
- >>> clustered_fs.model.add_constraints(...)
- >>> clustered_fs.solve(solver)
- """
- import numpy as np
-
- from .clustering import Clustering
- from .core import DataConverter, TimeSeriesData, drop_constant_arrays
-
- # Validation
- dt_min = float(self._fs.hours_per_timestep.min().item())
- dt_max = float(self._fs.hours_per_timestep.max().item())
- if dt_min != dt_max:
- raise ValueError(
- f'Clustering failed due to inconsistent time step sizes: '
- f'delta_t varies from {dt_min} to {dt_max} hours.'
- )
- ratio = parameters.hours_per_period / dt_max
- if not np.isclose(ratio, round(ratio), atol=1e-9):
- raise ValueError(
- f'The selected hours_per_period={parameters.hours_per_period} does not match the time '
- f'step size of {dt_max} hours. It must be an integer multiple of {dt_max} hours.'
- )
-
- logger.info(f'{"":#^80}')
- logger.info(f'{" Clustering TimeSeries Data ":#^80}')
-
- # Get dataset representation
- ds = self._fs.to_dataset()
- temporaly_changing_ds = drop_constant_arrays(ds, dim='time')
-
- # Perform clustering
- clustering = Clustering(
- original_data=temporaly_changing_ds.to_dataframe(),
- hours_per_time_step=float(dt_min),
- hours_per_period=parameters.hours_per_period,
- nr_of_periods=parameters.nr_of_periods,
- weights=self._calculate_clustering_weights(temporaly_changing_ds),
- time_series_for_high_peaks=parameters.labels_for_high_peaks,
- time_series_for_low_peaks=parameters.labels_for_low_peaks,
- )
- clustering.cluster()
-
- # Create new FlowSystem (with aggregated data if requested)
- if parameters.aggregate_data_and_fix_non_binary_vars:
- # Note: A second to_dataset() call is required here because:
- # 1. The first 'ds' (line 124) was processed by drop_constant_arrays()
- # 2. We need the full unprocessed dataset to apply aggregated data modifications
- # 3. The clustering used 'temporaly_changing_ds' for input, not the full 'ds'
- ds = self._fs.to_dataset()
- for name, series in clustering.aggregated_data.items():
- da = DataConverter.to_dataarray(series, self._fs.coords).rename(name).assign_attrs(ds[name].attrs)
- if TimeSeriesData.is_timeseries_data(da):
- da = TimeSeriesData.from_dataarray(da)
- ds[name] = da
-
- from .flow_system import FlowSystem
-
- clustered_fs = FlowSystem.from_dataset(ds)
- else:
- # Copy without data modification
- clustered_fs = self._fs.copy()
-
- # Store clustering info for later use
- clustered_fs._clustering_info = {
- 'parameters': parameters,
- 'clustering': clustering,
- 'components_to_clusterize': components_to_clusterize,
- 'original_fs': self._fs,
- }
-
- return clustered_fs
-
@staticmethod
def _calculate_clustering_weights(ds) -> dict[str, float]:
"""Calculate weights for clustering based on dataset attributes."""
@@ -195,7 +74,7 @@ def _calculate_clustering_weights(ds) -> dict[str, float]:
weights[name] = da.attrs.get('clustering_weight', 1)
if np.all(np.isclose(list(weights.values()), 1, atol=1e-6)):
- logger.info('All Clustering weights were set to 1')
+ logger.debug('All Clustering weights were set to 1')
return weights
@@ -696,8 +575,875 @@ def fix_sizes(
return new_fs
- # Future methods can be added here:
- #
- # def mga(self, alternatives: int = 5) -> FlowSystem:
- # """Create a FlowSystem configured for Modeling to Generate Alternatives."""
- # ...
+ def cluster(
+ self,
+ n_clusters: int,
+ cluster_duration: str | float,
+ weights: dict[str, float] | None = None,
+ time_series_for_high_peaks: list[str] | None = None,
+ time_series_for_low_peaks: list[str] | None = None,
+ cluster_method: Literal['k_means', 'k_medoids', 'hierarchical', 'k_maxoids', 'averaging'] = 'hierarchical',
+ representation_method: Literal[
+ 'meanRepresentation', 'medoidRepresentation', 'distributionAndMinMaxRepresentation'
+ ] = 'medoidRepresentation',
+ extreme_period_method: Literal['append', 'new_cluster_center', 'replace_cluster_center'] | None = None,
+ rescale_cluster_periods: bool = True,
+ predef_cluster_order: xr.DataArray | np.ndarray | list[int] | None = None,
+ **tsam_kwargs: Any,
+ ) -> FlowSystem:
+ """
+ Create a FlowSystem with reduced timesteps using typical clusters.
+
+ This method creates a new FlowSystem optimized for sizing studies by reducing
+ the number of timesteps to only the typical (representative) clusters identified
+ through time series aggregation using the tsam package.
+
+ The method:
+ 1. Performs time series clustering using tsam (hierarchical by default)
+ 2. Extracts only the typical clusters (not all original timesteps)
+ 3. Applies timestep weighting for accurate cost representation
+ 4. Handles storage states between clusters based on each Storage's ``cluster_mode``
+
+ Use this for initial sizing optimization, then use ``fix_sizes()`` to re-optimize
+ at full resolution for accurate dispatch results.
+
+ Args:
+ n_clusters: Number of clusters (typical periods) to extract (e.g., 8 typical days).
+ cluster_duration: Duration of each cluster. Can be a pandas-style string
+ ('1D', '24h', '6h') or a numeric value in hours.
+ weights: Optional clustering weights per time series. Keys are time series labels.
+ time_series_for_high_peaks: Time series labels for explicitly selecting high-value
+ clusters. **Recommended** for demand time series to capture peak demand days.
+ time_series_for_low_peaks: Time series labels for explicitly selecting low-value clusters.
+ cluster_method: Clustering algorithm to use. Options:
+ ``'hierarchical'`` (default), ``'k_means'``, ``'k_medoids'``,
+ ``'k_maxoids'``, ``'averaging'``.
+ representation_method: How cluster representatives are computed. Options:
+ ``'medoidRepresentation'`` (default), ``'meanRepresentation'``,
+ ``'distributionAndMinMaxRepresentation'``.
+ extreme_period_method: How extreme periods (peaks) are integrated. Options:
+ ``None`` (default, no special handling), ``'append'``,
+ ``'new_cluster_center'``, ``'replace_cluster_center'``.
+ rescale_cluster_periods: If True (default), rescale cluster periods so their
+ weighted mean matches the original time series mean.
+ predef_cluster_order: Predefined cluster assignments for manual clustering.
+ Array of cluster indices (0 to n_clusters-1) for each original period.
+ If provided, clustering is skipped and these assignments are used directly.
+ For multi-dimensional FlowSystems, use an xr.DataArray with dims
+ ``[original_cluster, period?, scenario?]`` to specify different assignments
+ per period/scenario combination.
+ **tsam_kwargs: Additional keyword arguments passed to
+ ``tsam.TimeSeriesAggregation``. See tsam documentation for all options.
+
+ Returns:
+ A new FlowSystem with reduced timesteps (only typical clusters).
+ The FlowSystem has metadata stored in ``clustering`` for expansion.
+
+ Raises:
+ ValueError: If timestep sizes are inconsistent.
+ ValueError: If cluster_duration is not a multiple of timestep size.
+
+ Examples:
+ Two-stage sizing optimization:
+
+ >>> # Stage 1: Size with reduced timesteps (fast)
+ >>> fs_sizing = flow_system.transform.cluster(
+ ... n_clusters=8,
+ ... cluster_duration='1D',
+ ... time_series_for_high_peaks=['HeatDemand(Q_th)|fixed_relative_profile'],
+ ... )
+ >>> fs_sizing.optimize(solver)
+ >>>
+ >>> # Apply safety margin (typical clusters may smooth peaks)
+ >>> sizes_with_margin = {
+ ... name: float(size.item()) * 1.05 for name, size in fs_sizing.statistics.sizes.items()
+ ... }
+ >>>
+ >>> # Stage 2: Fix sizes and re-optimize at full resolution
+ >>> fs_dispatch = flow_system.transform.fix_sizes(sizes_with_margin)
+ >>> fs_dispatch.optimize(solver)
+
+ Note:
+ - This is best suited for initial sizing, not final dispatch optimization
+ - Use ``time_series_for_high_peaks`` to ensure peak demand clusters are captured
+ - A 5-10% safety margin on sizes is recommended for the dispatch stage
+ - For seasonal storage (e.g., hydrogen, thermal storage), set
+ ``Storage.cluster_mode='intercluster'`` or ``'intercluster_cyclic'``
+ """
+ import tsam.timeseriesaggregation as tsam
+
+ from .clustering import Clustering, ClusterResult, ClusterStructure
+ from .core import TimeSeriesData, drop_constant_arrays
+ from .flow_system import FlowSystem
+
+ # Parse cluster_duration to hours
+ hours_per_cluster = (
+ pd.Timedelta(cluster_duration).total_seconds() / 3600
+ if isinstance(cluster_duration, str)
+ else float(cluster_duration)
+ )
+
+ # Validation
+ dt = float(self._fs.timestep_duration.min().item())
+ if not np.isclose(dt, float(self._fs.timestep_duration.max().item())):
+ raise ValueError(
+ f'cluster() requires uniform timestep sizes, got min={dt}h, '
+ f'max={float(self._fs.timestep_duration.max().item())}h.'
+ )
+ if not np.isclose(hours_per_cluster / dt, round(hours_per_cluster / dt), atol=1e-9):
+ raise ValueError(f'cluster_duration={hours_per_cluster}h must be a multiple of timestep size ({dt}h).')
+
+ timesteps_per_cluster = int(round(hours_per_cluster / dt))
+ has_periods = self._fs.periods is not None
+ has_scenarios = self._fs.scenarios is not None
+
+ # Determine iteration dimensions
+ periods = list(self._fs.periods) if has_periods else [None]
+ scenarios = list(self._fs.scenarios) if has_scenarios else [None]
+
+ ds = self._fs.to_dataset(include_solution=False)
+
+ # Validate tsam_kwargs doesn't override explicit parameters
+ reserved_tsam_keys = {
+ 'noTypicalPeriods',
+ 'hoursPerPeriod',
+ 'resolution',
+ 'clusterMethod',
+ 'extremePeriodMethod',
+ 'representationMethod',
+ 'rescaleClusterPeriods',
+ 'predefClusterOrder',
+ 'weightDict',
+ 'addPeakMax',
+ 'addPeakMin',
+ }
+ conflicts = reserved_tsam_keys & set(tsam_kwargs.keys())
+ if conflicts:
+ raise ValueError(
+ f'Cannot override explicit parameters via tsam_kwargs: {conflicts}. '
+ f'Use the corresponding cluster() parameters instead.'
+ )
+
+ # Validate predef_cluster_order dimensions if it's a DataArray
+ if isinstance(predef_cluster_order, xr.DataArray):
+ expected_dims = {'original_cluster'}
+ if has_periods:
+ expected_dims.add('period')
+ if has_scenarios:
+ expected_dims.add('scenario')
+ if set(predef_cluster_order.dims) != expected_dims:
+ raise ValueError(
+ f'predef_cluster_order dimensions {set(predef_cluster_order.dims)} '
+ f'do not match expected {expected_dims} for this FlowSystem.'
+ )
+
+ # Cluster each (period, scenario) combination using tsam directly
+ tsam_results: dict[tuple, tsam.TimeSeriesAggregation] = {}
+ cluster_orders: dict[tuple, np.ndarray] = {}
+ cluster_occurrences_all: dict[tuple, dict] = {}
+
+ # Collect metrics per (period, scenario) slice
+ clustering_metrics_all: dict[tuple, pd.DataFrame] = {}
+
+ for period_label in periods:
+ for scenario_label in scenarios:
+ key = (period_label, scenario_label)
+ selector = {k: v for k, v in [('period', period_label), ('scenario', scenario_label)] if v is not None}
+ ds_slice = ds.sel(**selector, drop=True) if selector else ds
+ temporaly_changing_ds = drop_constant_arrays(ds_slice, dim='time')
+ df = temporaly_changing_ds.to_dataframe()
+
+ if selector:
+ logger.info(f'Clustering {", ".join(f"{k}={v}" for k, v in selector.items())}...')
+
+ # Handle predef_cluster_order for multi-dimensional case
+ predef_order_slice = None
+ if predef_cluster_order is not None:
+ if isinstance(predef_cluster_order, xr.DataArray):
+ # Extract slice for this (period, scenario) combination
+ predef_order_slice = predef_cluster_order.sel(**selector, drop=True).values
+ else:
+ # Simple array/list - use directly
+ predef_order_slice = predef_cluster_order
+
+ # Use tsam directly
+ clustering_weights = weights or self._calculate_clustering_weights(temporaly_changing_ds)
+ # tsam expects 'None' as a string, not Python None
+ tsam_extreme_method = 'None' if extreme_period_method is None else extreme_period_method
+ tsam_agg = tsam.TimeSeriesAggregation(
+ df,
+ noTypicalPeriods=n_clusters,
+ hoursPerPeriod=hours_per_cluster,
+ resolution=dt,
+ clusterMethod=cluster_method,
+ extremePeriodMethod=tsam_extreme_method,
+ representationMethod=representation_method,
+ rescaleClusterPeriods=rescale_cluster_periods,
+ predefClusterOrder=predef_order_slice,
+ weightDict={name: w for name, w in clustering_weights.items() if name in df.columns},
+ addPeakMax=time_series_for_high_peaks or [],
+ addPeakMin=time_series_for_low_peaks or [],
+ **tsam_kwargs,
+ )
+ # Suppress tsam warning about minimal value constraints (informational, not actionable)
+ with warnings.catch_warnings():
+ warnings.filterwarnings('ignore', category=UserWarning, message='.*minimal value.*exceeds.*')
+ tsam_agg.createTypicalPeriods()
+
+ tsam_results[key] = tsam_agg
+ cluster_orders[key] = tsam_agg.clusterOrder
+ cluster_occurrences_all[key] = tsam_agg.clusterPeriodNoOccur
+ # Compute accuracy metrics with error handling
+ try:
+ clustering_metrics_all[key] = tsam_agg.accuracyIndicators()
+ except Exception as e:
+ logger.warning(f'Failed to compute clustering metrics for {key}: {e}')
+ clustering_metrics_all[key] = pd.DataFrame()
+
+ # Use first result for structure
+ first_key = (periods[0], scenarios[0])
+ first_tsam = tsam_results[first_key]
+
+ # Convert metrics to xr.Dataset with period/scenario dims if multi-dimensional
+ # Filter out empty DataFrames (from failed accuracyIndicators calls)
+ non_empty_metrics = {k: v for k, v in clustering_metrics_all.items() if not v.empty}
+ if not non_empty_metrics:
+ # All metrics failed - create empty Dataset
+ clustering_metrics = xr.Dataset()
+ elif len(non_empty_metrics) == 1 or len(clustering_metrics_all) == 1:
+ # Simple case: convert single DataFrame to Dataset
+ metrics_df = non_empty_metrics.get(first_key)
+ if metrics_df is None:
+ metrics_df = next(iter(non_empty_metrics.values()))
+ clustering_metrics = xr.Dataset(
+ {
+ col: xr.DataArray(
+ metrics_df[col].values, dims=['time_series'], coords={'time_series': metrics_df.index}
+ )
+ for col in metrics_df.columns
+ }
+ )
+ else:
+ # Multi-dim case: combine metrics into Dataset with period/scenario dims
+ # First, get the metric columns from any non-empty DataFrame
+ sample_df = next(iter(non_empty_metrics.values()))
+ metric_names = list(sample_df.columns)
+ time_series_names = list(sample_df.index)
+
+ # Build DataArrays for each metric
+ data_vars = {}
+ for metric in metric_names:
+ # Shape: (time_series, period?, scenario?)
+ slices = {}
+ for (p, s), df in clustering_metrics_all.items():
+ if df.empty:
+ # Use NaN for failed metrics
+ slices[(p, s)] = xr.DataArray(np.full(len(time_series_names), np.nan), dims=['time_series'])
+ else:
+ slices[(p, s)] = xr.DataArray(df[metric].values, dims=['time_series'])
+
+ da = self._combine_slices_to_dataarray_generic(slices, ['time_series'], periods, scenarios, metric)
+ da = da.assign_coords(time_series=time_series_names)
+ data_vars[metric] = da
+
+ clustering_metrics = xr.Dataset(data_vars)
+ n_reduced_timesteps = len(first_tsam.typicalPeriods)
+ actual_n_clusters = len(first_tsam.clusterPeriodNoOccur)
+
+ # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+ # TRUE (cluster, time) DIMENSIONS
+ # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
+ # Create coordinates for the 2D cluster structure
+ cluster_coords = np.arange(actual_n_clusters)
+ # Use DatetimeIndex for time within cluster (e.g., 00:00-23:00 for daily clustering)
+ time_coords = pd.date_range(
+ start='2000-01-01',
+ periods=timesteps_per_cluster,
+ freq=pd.Timedelta(hours=dt),
+ name='time',
+ )
+
+ # Create cluster_weight: shape (cluster,) - one weight per cluster
+ # This is the number of original periods each cluster represents
+ def _build_cluster_weight_for_key(key: tuple) -> xr.DataArray:
+ occurrences = cluster_occurrences_all[key]
+ weights = np.array([occurrences.get(c, 1) for c in range(actual_n_clusters)])
+ return xr.DataArray(weights, dims=['cluster'], coords={'cluster': cluster_coords})
+
+ # Build cluster_weight - use _combine_slices_to_dataarray_generic for multi-dim handling
+ weight_slices = {key: _build_cluster_weight_for_key(key) for key in cluster_occurrences_all}
+ cluster_weight = self._combine_slices_to_dataarray_generic(
+ weight_slices, ['cluster'], periods, scenarios, 'cluster_weight'
+ )
+
+ logger.info(
+ f'Reduced from {len(self._fs.timesteps)} to {actual_n_clusters} clusters Γ {timesteps_per_cluster} timesteps'
+ )
+ logger.info(f'Clusters: {actual_n_clusters} (requested: {n_clusters})')
+
+ # Build typical periods DataArrays with (cluster, time) shape
+ typical_das: dict[str, dict[tuple, xr.DataArray]] = {}
+ for key, tsam_agg in tsam_results.items():
+ typical_df = tsam_agg.typicalPeriods
+ for col in typical_df.columns:
+ # Reshape flat data to (cluster, time)
+ flat_data = typical_df[col].values
+ reshaped = flat_data.reshape(actual_n_clusters, timesteps_per_cluster)
+ typical_das.setdefault(col, {})[key] = xr.DataArray(
+ reshaped,
+ dims=['cluster', 'time'],
+ coords={'cluster': cluster_coords, 'time': time_coords},
+ )
+
+ # Build reduced dataset with (cluster, time) dimensions
+ all_keys = {(p, s) for p in periods for s in scenarios}
+ ds_new_vars = {}
+ for name, original_da in ds.data_vars.items():
+ if 'time' not in original_da.dims:
+ ds_new_vars[name] = original_da.copy()
+ elif name not in typical_das or set(typical_das[name].keys()) != all_keys:
+ # Time-dependent but constant: reshape to (cluster, time, ...)
+ sliced = original_da.isel(time=slice(0, n_reduced_timesteps))
+ # Get the shape - time is first, other dims follow
+ other_dims = [d for d in sliced.dims if d != 'time']
+ other_shape = [sliced.sizes[d] for d in other_dims]
+ # Reshape: (n_reduced_timesteps, ...) -> (n_clusters, timesteps_per_cluster, ...)
+ new_shape = [actual_n_clusters, timesteps_per_cluster] + other_shape
+ reshaped = sliced.values.reshape(new_shape)
+ # Build coords
+ new_coords = {'cluster': cluster_coords, 'time': time_coords}
+ for dim in other_dims:
+ new_coords[dim] = sliced.coords[dim].values
+ ds_new_vars[name] = xr.DataArray(
+ reshaped,
+ dims=['cluster', 'time'] + other_dims,
+ coords=new_coords,
+ attrs=original_da.attrs,
+ )
+ else:
+ # Time-varying: combine per-(period, scenario) slices with (cluster, time) dims
+ da = self._combine_slices_to_dataarray_2d(
+ slices=typical_das[name],
+ original_da=original_da,
+ cluster_coords=cluster_coords,
+ time_coords=time_coords,
+ periods=periods,
+ scenarios=scenarios,
+ )
+ if TimeSeriesData.is_timeseries_data(original_da):
+ da = TimeSeriesData.from_dataarray(da.assign_attrs(original_da.attrs))
+ ds_new_vars[name] = da
+
+ # Copy attrs but remove cluster_weight - the clustered FlowSystem gets its own
+ # cluster_weight set after from_dataset (original reference has wrong shape)
+ new_attrs = dict(ds.attrs)
+ new_attrs.pop('cluster_weight', None)
+ ds_new = xr.Dataset(ds_new_vars, attrs=new_attrs)
+ ds_new.attrs['timesteps_per_cluster'] = timesteps_per_cluster
+ ds_new.attrs['timestep_duration'] = dt
+ ds_new.attrs['n_clusters'] = actual_n_clusters
+ ds_new.attrs['is_clustered'] = True
+
+ reduced_fs = FlowSystem.from_dataset(ds_new)
+ # Set cluster_weight - shape (cluster,) possibly with period/scenario dimensions
+ reduced_fs.cluster_weight = cluster_weight
+
+ # Remove 'equals_final' from storages - doesn't make sense on reduced timesteps
+ # Set to None so initial SOC is free (handled by storage_mode constraints)
+ for storage in reduced_fs.storages.values():
+ ics = storage.initial_charge_state
+ if isinstance(ics, str) and ics == 'equals_final':
+ storage.initial_charge_state = None
+
+ # Build Clustering for inter-cluster linking and solution expansion
+ n_original_timesteps = len(self._fs.timesteps)
+
+ # Build per-slice cluster_order and timestep_mapping as multi-dimensional DataArrays
+ # This is needed because each (period, scenario) combination may have different clustering
+
+ def _build_timestep_mapping_for_key(key: tuple) -> np.ndarray:
+ """Build timestep_mapping for a single (period, scenario) slice."""
+ mapping = np.zeros(n_original_timesteps, dtype=np.int32)
+ for period_idx, cluster_id in enumerate(cluster_orders[key]):
+ for pos in range(timesteps_per_cluster):
+ original_idx = period_idx * timesteps_per_cluster + pos
+ if original_idx < n_original_timesteps:
+ representative_idx = cluster_id * timesteps_per_cluster + pos
+ mapping[original_idx] = representative_idx
+ return mapping
+
+ def _build_cluster_occurrences_for_key(key: tuple) -> np.ndarray:
+ """Build cluster_occurrences array for a single (period, scenario) slice."""
+ occurrences = cluster_occurrences_all[key]
+ return np.array([occurrences.get(c, 0) for c in range(actual_n_clusters)])
+
+ # Build multi-dimensional arrays
+ if has_periods or has_scenarios:
+ # Multi-dimensional case: build arrays for each (period, scenario) combination
+ # cluster_order: dims [original_cluster, period?, scenario?]
+ cluster_order_slices = {}
+ timestep_mapping_slices = {}
+ cluster_occurrences_slices = {}
+
+ # Use renamed timesteps as coordinates for multi-dimensional case
+ original_timesteps_coord = self._fs.timesteps.rename('original_time')
+
+ for p in periods:
+ for s in scenarios:
+ key = (p, s)
+ cluster_order_slices[key] = xr.DataArray(
+ cluster_orders[key], dims=['original_cluster'], name='cluster_order'
+ )
+ timestep_mapping_slices[key] = xr.DataArray(
+ _build_timestep_mapping_for_key(key),
+ dims=['original_time'],
+ coords={'original_time': original_timesteps_coord},
+ name='timestep_mapping',
+ )
+ cluster_occurrences_slices[key] = xr.DataArray(
+ _build_cluster_occurrences_for_key(key), dims=['cluster'], name='cluster_occurrences'
+ )
+
+ # Combine slices into multi-dimensional DataArrays
+ cluster_order_da = self._combine_slices_to_dataarray_generic(
+ cluster_order_slices, ['original_cluster'], periods, scenarios, 'cluster_order'
+ )
+ timestep_mapping_da = self._combine_slices_to_dataarray_generic(
+ timestep_mapping_slices, ['original_time'], periods, scenarios, 'timestep_mapping'
+ )
+ cluster_occurrences_da = self._combine_slices_to_dataarray_generic(
+ cluster_occurrences_slices, ['cluster'], periods, scenarios, 'cluster_occurrences'
+ )
+ else:
+ # Simple case: single (None, None) slice
+ cluster_order_da = xr.DataArray(cluster_orders[first_key], dims=['original_cluster'], name='cluster_order')
+ # Use renamed timesteps as coordinates
+ original_timesteps_coord = self._fs.timesteps.rename('original_time')
+ timestep_mapping_da = xr.DataArray(
+ _build_timestep_mapping_for_key(first_key),
+ dims=['original_time'],
+ coords={'original_time': original_timesteps_coord},
+ name='timestep_mapping',
+ )
+ cluster_occurrences_da = xr.DataArray(
+ _build_cluster_occurrences_for_key(first_key), dims=['cluster'], name='cluster_occurrences'
+ )
+
+ cluster_structure = ClusterStructure(
+ cluster_order=cluster_order_da,
+ cluster_occurrences=cluster_occurrences_da,
+ n_clusters=actual_n_clusters,
+ timesteps_per_cluster=timesteps_per_cluster,
+ )
+
+ # Create representative_weights with (cluster,) dimension only
+ # Each cluster has one weight (same for all timesteps within it)
+ def _build_cluster_weights_for_key(key: tuple) -> xr.DataArray:
+ occurrences = cluster_occurrences_all[key]
+ # Shape: (n_clusters,) - one weight per cluster
+ weights = np.array([occurrences.get(c, 1) for c in range(actual_n_clusters)])
+ return xr.DataArray(weights, dims=['cluster'], name='representative_weights')
+
+ weights_slices = {key: _build_cluster_weights_for_key(key) for key in cluster_occurrences_all}
+ representative_weights = self._combine_slices_to_dataarray_generic(
+ weights_slices, ['cluster'], periods, scenarios, 'representative_weights'
+ )
+
+ aggregation_result = ClusterResult(
+ timestep_mapping=timestep_mapping_da,
+ n_representatives=n_reduced_timesteps,
+ representative_weights=representative_weights,
+ cluster_structure=cluster_structure,
+ original_data=ds,
+ aggregated_data=ds_new,
+ )
+
+ reduced_fs.clustering = Clustering(
+ result=aggregation_result,
+ backend_name='tsam',
+ metrics=clustering_metrics,
+ )
+
+ return reduced_fs
+
+ @staticmethod
+ def _combine_slices_to_dataarray(
+ slices: dict[tuple, xr.DataArray],
+ original_da: xr.DataArray,
+ new_time_index: pd.DatetimeIndex,
+ periods: list,
+ scenarios: list,
+ ) -> xr.DataArray:
+ """Combine per-(period, scenario) slices into a multi-dimensional DataArray using xr.concat.
+
+ Args:
+ slices: Dict mapping (period, scenario) tuples to 1D DataArrays (time only).
+ original_da: Original DataArray to get dimension order and attrs from.
+ new_time_index: New time coordinate for the output.
+ periods: List of period labels ([None] if no periods dimension).
+ scenarios: List of scenario labels ([None] if no scenarios dimension).
+
+ Returns:
+ DataArray with dimensions matching original_da but reduced time.
+ """
+ first_key = (periods[0], scenarios[0])
+ has_periods = periods != [None]
+ has_scenarios = scenarios != [None]
+
+ # Simple case: no period/scenario dimensions
+ if not has_periods and not has_scenarios:
+ return slices[first_key].assign_attrs(original_da.attrs)
+
+ # Multi-dimensional: use xr.concat to stack along period/scenario dims
+ if has_periods and has_scenarios:
+ # Stack scenarios first, then periods
+ period_arrays = []
+ for p in periods:
+ scenario_arrays = [slices[(p, s)] for s in scenarios]
+ period_arrays.append(xr.concat(scenario_arrays, dim=pd.Index(scenarios, name='scenario')))
+ result = xr.concat(period_arrays, dim=pd.Index(periods, name='period'))
+ elif has_periods:
+ result = xr.concat([slices[(p, None)] for p in periods], dim=pd.Index(periods, name='period'))
+ else:
+ result = xr.concat([slices[(None, s)] for s in scenarios], dim=pd.Index(scenarios, name='scenario'))
+
+ # Put time dimension first (standard order), preserve other dims
+ result = result.transpose('time', ...)
+
+ return result.assign_attrs(original_da.attrs)
+
+ @staticmethod
+ def _combine_slices_to_dataarray_generic(
+ slices: dict[tuple, xr.DataArray],
+ base_dims: list[str],
+ periods: list,
+ scenarios: list,
+ name: str,
+ ) -> xr.DataArray:
+ """Combine per-(period, scenario) slices into a multi-dimensional DataArray.
+
+ Generic version that works with any base dimension (not just 'time').
+
+ Args:
+ slices: Dict mapping (period, scenario) tuples to DataArrays.
+ base_dims: Base dimensions of each slice (e.g., ['original_cluster'] or ['original_time']).
+ periods: List of period labels ([None] if no periods dimension).
+ scenarios: List of scenario labels ([None] if no scenarios dimension).
+ name: Name for the resulting DataArray.
+
+ Returns:
+ DataArray with dimensions [base_dims..., period?, scenario?].
+ """
+ first_key = (periods[0], scenarios[0])
+ has_periods = periods != [None]
+ has_scenarios = scenarios != [None]
+
+ # Simple case: no period/scenario dimensions
+ if not has_periods and not has_scenarios:
+ return slices[first_key].rename(name)
+
+ # Multi-dimensional: use xr.concat to stack along period/scenario dims
+ if has_periods and has_scenarios:
+ # Stack scenarios first, then periods
+ period_arrays = []
+ for p in periods:
+ scenario_arrays = [slices[(p, s)] for s in scenarios]
+ period_arrays.append(xr.concat(scenario_arrays, dim=pd.Index(scenarios, name='scenario')))
+ result = xr.concat(period_arrays, dim=pd.Index(periods, name='period'))
+ elif has_periods:
+ result = xr.concat([slices[(p, None)] for p in periods], dim=pd.Index(periods, name='period'))
+ else:
+ result = xr.concat([slices[(None, s)] for s in scenarios], dim=pd.Index(scenarios, name='scenario'))
+
+ # Put base dimension first (standard order)
+ result = result.transpose(base_dims[0], ...)
+
+ return result.rename(name)
+
+ @staticmethod
+ def _combine_slices_to_dataarray_2d(
+ slices: dict[tuple, xr.DataArray],
+ original_da: xr.DataArray,
+ cluster_coords: np.ndarray,
+ time_coords: np.ndarray,
+ periods: list,
+ scenarios: list,
+ ) -> xr.DataArray:
+ """Combine per-(period, scenario) slices into a multi-dimensional DataArray with (cluster, time) dims.
+
+ Args:
+ slices: Dict mapping (period, scenario) tuples to DataArrays with (cluster, time) dims.
+ original_da: Original DataArray to get attrs from.
+ cluster_coords: Cluster coordinate values.
+ time_coords: Within-cluster time coordinate values.
+ periods: List of period labels ([None] if no periods dimension).
+ scenarios: List of scenario labels ([None] if no scenarios dimension).
+
+ Returns:
+ DataArray with dimensions (cluster, time, period?, scenario?).
+ """
+ first_key = (periods[0], scenarios[0])
+ has_periods = periods != [None]
+ has_scenarios = scenarios != [None]
+
+ # Simple case: no period/scenario dimensions
+ if not has_periods and not has_scenarios:
+ return slices[first_key].assign_attrs(original_da.attrs)
+
+ # Multi-dimensional: use xr.concat to stack along period/scenario dims
+ if has_periods and has_scenarios:
+ # Stack scenarios first, then periods
+ period_arrays = []
+ for p in periods:
+ scenario_arrays = [slices[(p, s)] for s in scenarios]
+ period_arrays.append(xr.concat(scenario_arrays, dim=pd.Index(scenarios, name='scenario')))
+ result = xr.concat(period_arrays, dim=pd.Index(periods, name='period'))
+ elif has_periods:
+ result = xr.concat([slices[(p, None)] for p in periods], dim=pd.Index(periods, name='period'))
+ else:
+ result = xr.concat([slices[(None, s)] for s in scenarios], dim=pd.Index(scenarios, name='scenario'))
+
+ # Put cluster and time first (standard order for clustered data)
+ result = result.transpose('cluster', 'time', ...)
+
+ return result.assign_attrs(original_da.attrs)
+
+ def expand_solution(self) -> FlowSystem:
+ """Expand a reduced (clustered) FlowSystem back to full original timesteps.
+
+ After solving a FlowSystem created with ``cluster()``, this method
+ disaggregates the FlowSystem by:
+ 1. Expanding all time series data from typical clusters to full timesteps
+ 2. Expanding the solution by mapping each typical cluster back to all
+ original clusters it represents
+
+ For FlowSystems with periods and/or scenarios, each (period, scenario)
+ combination is expanded using its own cluster assignment.
+
+ This enables using all existing solution accessors (``statistics``, ``plot``, etc.)
+ with full time resolution, where both the data and solution are consistently
+ expanded from the typical clusters.
+
+ Returns:
+ FlowSystem: A new FlowSystem with full timesteps and expanded solution.
+
+ Raises:
+ ValueError: If the FlowSystem was not created with ``cluster()``.
+ ValueError: If the FlowSystem has no solution.
+
+ Examples:
+ Two-stage optimization with solution expansion:
+
+ >>> # Stage 1: Size with reduced timesteps
+ >>> fs_reduced = flow_system.transform.cluster(
+ ... n_clusters=8,
+ ... cluster_duration='1D',
+ ... )
+ >>> fs_reduced.optimize(solver)
+ >>>
+ >>> # Expand to full resolution FlowSystem
+ >>> fs_expanded = fs_reduced.transform.expand_solution()
+ >>>
+ >>> # Use all existing accessors with full timesteps
+ >>> fs_expanded.statistics.flow_rates # Full 8760 timesteps
+ >>> fs_expanded.statistics.plot.balance('HeatBus') # Full resolution plots
+ >>> fs_expanded.statistics.plot.heatmap('Boiler(Q_th)|flow_rate')
+
+ Note:
+ The expanded FlowSystem repeats the typical cluster values for all
+ original clusters belonging to the same cluster. Both input data and solution
+ are consistently expanded, so they match. This is an approximation -
+ the actual dispatch at full resolution would differ due to
+ intra-cluster variations in time series data.
+
+ For accurate dispatch results, use ``fix_sizes()`` to fix the sizes
+ from the reduced optimization and re-optimize at full resolution.
+ """
+ from .flow_system import FlowSystem
+
+ # Validate
+ if self._fs.clustering is None:
+ raise ValueError(
+ 'expand_solution() requires a FlowSystem created with cluster(). '
+ 'This FlowSystem has no aggregation info.'
+ )
+ if self._fs.solution is None:
+ raise ValueError('FlowSystem has no solution. Run optimize() or solve() first.')
+
+ info = self._fs.clustering
+ cluster_structure = info.result.cluster_structure
+ if cluster_structure is None:
+ raise ValueError('No cluster structure available for expansion.')
+
+ timesteps_per_cluster = cluster_structure.timesteps_per_cluster
+ n_clusters = (
+ int(cluster_structure.n_clusters)
+ if isinstance(cluster_structure.n_clusters, (int, np.integer))
+ else int(cluster_structure.n_clusters.values)
+ )
+
+ # Get original timesteps from clustering, but periods/scenarios from the FlowSystem
+ # (the clustered FlowSystem preserves the same periods/scenarios)
+ original_timesteps = info.original_timesteps
+ has_periods = self._fs.periods is not None
+ has_scenarios = self._fs.scenarios is not None
+
+ periods = list(self._fs.periods) if has_periods else [None]
+ scenarios = list(self._fs.scenarios) if has_scenarios else [None]
+ n_original_timesteps = len(original_timesteps)
+ n_reduced_timesteps = n_clusters * timesteps_per_cluster
+ n_original_clusters = cluster_structure.n_original_clusters
+
+ # Expand function using ClusterResult.expand_data() - handles multi-dimensional cases
+ # For charge_state with cluster dim, also includes the extra timestep
+ # Clamp to valid bounds to handle partial clusters at the end
+ last_original_cluster_idx = min(
+ (n_original_timesteps - 1) // timesteps_per_cluster,
+ n_original_clusters - 1,
+ )
+
+ def expand_da(da: xr.DataArray, var_name: str = '') -> xr.DataArray:
+ if 'time' not in da.dims:
+ return da.copy()
+ expanded = info.result.expand_data(da, original_time=original_timesteps)
+
+ # For charge_state with cluster dim, append the extra timestep value
+ if var_name.endswith('|charge_state') and 'cluster' in da.dims:
+ # Get extra timestep from last cluster using vectorized selection
+ cluster_order = cluster_structure.cluster_order # (n_original_clusters,) or with period/scenario
+ if cluster_order.ndim == 1:
+ last_cluster = int(cluster_order[last_original_cluster_idx])
+ extra_val = da.isel(cluster=last_cluster, time=-1)
+ else:
+ # Multi-dimensional: select last cluster for each period/scenario slice
+ last_clusters = cluster_order.isel(original_cluster=last_original_cluster_idx)
+ extra_val = da.isel(cluster=last_clusters, time=-1)
+ # Drop 'cluster'/'time' coords created by isel (kept as non-dim coords)
+ extra_val = extra_val.drop_vars(['cluster', 'time'], errors='ignore')
+ extra_val = extra_val.expand_dims(time=[original_timesteps_extra[-1]])
+ expanded = xr.concat([expanded, extra_val], dim='time')
+
+ return expanded
+
+ # 1. Expand FlowSystem data (with cluster_weight set to 1.0 for all timesteps)
+ reduced_ds = self._fs.to_dataset(include_solution=False)
+ # Filter out cluster-related variables and copy attrs without clustering info
+ data_vars = {
+ name: expand_da(da, name)
+ for name, da in reduced_ds.data_vars.items()
+ if name != 'cluster_weight' and not name.startswith('clustering|')
+ }
+ attrs = {
+ k: v
+ for k, v in reduced_ds.attrs.items()
+ if k not in ('is_clustered', 'n_clusters', 'timesteps_per_cluster', 'clustering')
+ }
+ expanded_ds = xr.Dataset(data_vars, attrs=attrs)
+ # Compute timestep_duration from original timesteps
+ # Add extra timestep for duration calculation (assume same interval as last)
+ original_timesteps_extra = FlowSystem._create_timesteps_with_extra(original_timesteps, None)
+ timestep_duration = FlowSystem.calculate_timestep_duration(original_timesteps_extra)
+ expanded_ds.attrs['timestep_duration'] = timestep_duration.values.tolist()
+
+ # Create cluster_weight with value 1.0 for all timesteps (no weighting needed for expanded)
+ # Use _combine_slices_to_dataarray for consistent multi-dim handling
+ ones_da = xr.DataArray(np.ones(n_original_timesteps), dims=['time'], coords={'time': original_timesteps})
+ ones_slices = {(p, s): ones_da for p in periods for s in scenarios}
+ cluster_weight = self._combine_slices_to_dataarray(
+ ones_slices, ones_da, original_timesteps, periods, scenarios
+ ).rename('cluster_weight')
+ expanded_ds['cluster_weight'] = cluster_weight
+
+ expanded_fs = FlowSystem.from_dataset(expanded_ds)
+
+ # 2. Expand solution
+ # charge_state variables get their extra timestep via expand_da; others get NaN via reindex
+ reduced_solution = self._fs.solution
+ expanded_fs._solution = xr.Dataset(
+ {name: expand_da(da, name) for name, da in reduced_solution.data_vars.items()},
+ attrs=reduced_solution.attrs,
+ )
+ # Reindex to timesteps_extra for consistency with non-expanded FlowSystems
+ # (variables without extra timestep data will have NaN at the final timestep)
+ expanded_fs._solution = expanded_fs._solution.reindex(time=original_timesteps_extra)
+
+ # 3. Combine charge_state with SOC_boundary for InterclusterStorageModel storages
+ # For intercluster storages, charge_state is relative (ΞE) and can be negative.
+ # Per Blanke et al. (2022) Eq. 9, actual SOC at time t in period d is:
+ # SOC(t) = SOC_boundary[d] * (1 - loss)^t_within_period + charge_state(t)
+ # where t_within_period is hours from period start (accounts for self-discharge decay).
+ n_original_timesteps_extra = len(original_timesteps_extra)
+ soc_boundary_vars = [name for name in reduced_solution.data_vars if name.endswith('|SOC_boundary')]
+ for soc_boundary_name in soc_boundary_vars:
+ storage_name = soc_boundary_name.rsplit('|', 1)[0]
+ charge_state_name = f'{storage_name}|charge_state'
+ if charge_state_name not in expanded_fs._solution:
+ continue
+
+ soc_boundary = reduced_solution[soc_boundary_name]
+ expanded_charge_state = expanded_fs._solution[charge_state_name]
+
+ # Map each original timestep (including extra) to its original period index
+ # The extra timestep belongs to the last period
+ original_cluster_indices = np.minimum(
+ np.arange(n_original_timesteps_extra) // timesteps_per_cluster,
+ n_original_clusters - 1,
+ )
+
+ # Select SOC_boundary for each timestep (boundary[d] for period d)
+ # SOC_boundary has dim 'cluster_boundary', we select indices 0..n_original_clusters-1
+ soc_boundary_per_timestep = soc_boundary.isel(
+ cluster_boundary=xr.DataArray(original_cluster_indices, dims=['time'])
+ )
+ soc_boundary_per_timestep = soc_boundary_per_timestep.assign_coords(time=original_timesteps_extra)
+
+ # Apply self-discharge decay to SOC_boundary based on time within period
+ # Get the storage's relative_loss_per_hour from the clustered flow system
+ storage = self._fs.storages.get(storage_name)
+ if storage is not None:
+ # Time within period for each timestep (0, 1, 2, ..., timesteps_per_cluster-1, 0, 1, ...)
+ # The extra timestep is at index timesteps_per_cluster (one past the last within-cluster index)
+ time_within_period = np.arange(n_original_timesteps_extra) % timesteps_per_cluster
+ # The extra timestep gets the correct decay (timesteps_per_cluster)
+ time_within_period[-1] = timesteps_per_cluster
+ time_within_period_da = xr.DataArray(
+ time_within_period, dims=['time'], coords={'time': original_timesteps_extra}
+ )
+ # Decay factor: (1 - loss)^t, using mean loss over time
+ loss_value = storage.relative_loss_per_hour.mean('time')
+ if (loss_value > 0).any():
+ decay_da = (1 - loss_value) ** time_within_period_da
+ if 'cluster' in decay_da.dims:
+ # Map each timestep to its cluster's decay value
+ cluster_per_timestep = cluster_structure.cluster_order.values[original_cluster_indices]
+ decay_da = decay_da.isel(cluster=xr.DataArray(cluster_per_timestep, dims=['time'])).drop_vars(
+ 'cluster', errors='ignore'
+ )
+ soc_boundary_per_timestep = soc_boundary_per_timestep * decay_da
+
+ # Combine: actual_SOC = SOC_boundary * decay + charge_state
+ # Clip to non-negative since actual SOC cannot be negative
+ # (small negative values may occur due to constraint approximations in the model)
+ combined_charge_state = (expanded_charge_state + soc_boundary_per_timestep).clip(min=0)
+ expanded_fs._solution[charge_state_name] = combined_charge_state.assign_attrs(expanded_charge_state.attrs)
+
+ # Remove SOC_boundary variables - they're cluster-specific and now incorporated into charge_state
+ for soc_boundary_name in soc_boundary_vars:
+ if soc_boundary_name in expanded_fs._solution:
+ del expanded_fs._solution[soc_boundary_name]
+ # Also drop the cluster_boundary coordinate (orphaned after removing SOC_boundary)
+ if 'cluster_boundary' in expanded_fs._solution.coords:
+ expanded_fs._solution = expanded_fs._solution.drop_vars('cluster_boundary')
+
+ n_combinations = len(periods) * len(scenarios)
+ logger.info(
+ f'Expanded FlowSystem from {n_reduced_timesteps} to {n_original_timesteps} timesteps '
+ f'({n_clusters} clusters'
+ + (
+ f', {n_combinations} period/scenario combinations)'
+ if n_combinations > 1
+ else f' β {n_original_clusters} original clusters)'
+ )
+ )
+
+ return expanded_fs
diff --git a/mkdocs.yml b/mkdocs.yml
index 551fac523..9eed96ad6 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -71,8 +71,14 @@ nav:
- Scenarios: notebooks/07-scenarios-and-periods.ipynb
- Aggregation: notebooks/08a-aggregation.ipynb
- Rolling Horizon: notebooks/08b-rolling-horizon.ipynb
+ - Clustering:
+ - Introduction: notebooks/08c-clustering.ipynb
+ - Storage Modes: notebooks/08c2-clustering-storage-modes.ipynb
+ - Multi-Period: notebooks/08d-clustering-multiperiod.ipynb
+ - Internals: notebooks/08e-clustering-internals.ipynb
- Results:
- Plotting: notebooks/09-plotting-and-data-access.ipynb
+ - Custom Data Plotting: notebooks/fxplot_accessor_demo.ipynb
- API Reference: api-reference/
@@ -229,10 +235,14 @@ plugins:
separator: '[\s\u200b\-_,:!=\[\]()"`/]+|\.(?!\d)|&[lg]t;|(?!\b)(?=[A-Z][a-z])'
- mkdocs-jupyter:
- execute: true # Execute notebooks during build
+ execute: !ENV [MKDOCS_JUPYTER_EXECUTE, true] # CI pre-executes in parallel
allow_errors: false
include_source: true
include_requirejs: true
+ ignore:
+ - "notebooks/data/*.py" # Data generation scripts, not notebooks
+ execute_ignore:
+ - "notebooks/data/*.py"
- plotly
diff --git a/pyproject.toml b/pyproject.toml
index e28b3048e..f80f83557 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -110,6 +110,10 @@ docs = [
"mkdocs-git-revision-date-localized-plugin==1.5.0",
"mkdocs-minify-plugin==0.8.0",
"notebook>=7.5.0",
+ # Realistic profile generation for examples
+ "demandlib >= 0.2.2, < 0.3",
+ "pvlib >= 0.10.0, < 0.14",
+ "holidays >= 0.40, < 1",
]
[project.urls]
@@ -205,17 +209,11 @@ filterwarnings = [
"ignore:SegmentedResults is deprecated:DeprecationWarning:flixopt",
"ignore:ClusteredOptimization is deprecated:DeprecationWarning:flixopt",
- # === Treat flixopt warnings as errors (strict mode for our code) ===
+ # === Treat most flixopt warnings as errors (strict mode for our code) ===
# This ensures we catch deprecations, future changes, and user warnings in our own code
"error::DeprecationWarning:flixopt",
"error::FutureWarning:flixopt",
"error::UserWarning:flixopt",
-
- # === Third-party warnings (mirrored from __init__.py) ===
- "ignore:.*minimal value.*exceeds.*:UserWarning:tsam",
- "ignore:Coordinates across variables not equal:UserWarning:linopy",
- "ignore:.*join will change from join='outer' to join='exact'.*:FutureWarning:linopy",
- "ignore:numpy\\.ndarray size changed:RuntimeWarning",
"ignore:.*network visualization is still experimental.*:UserWarning:flixopt",
]
diff --git a/tests/deprecated/examples/03_Optimization_modes/example_optimization_modes.py b/tests/deprecated/examples/03_Optimization_modes/example_optimization_modes.py
index e85c4329e..02e167c40 100644
--- a/tests/deprecated/examples/03_Optimization_modes/example_optimization_modes.py
+++ b/tests/deprecated/examples/03_Optimization_modes/example_optimization_modes.py
@@ -33,15 +33,10 @@ def get_solutions(optimizations: list, variable: str) -> xr.Dataset:
# Segmented Properties
segment_length, overlap_length = 96, 1
- # Aggregated Properties
- clustering_parameters = fx.ClusteringParameters(
- hours_per_period=6,
- nr_of_periods=4,
- fix_storage_flows=False,
- aggregate_data_and_fix_non_binary_vars=True,
- percentage_of_period_freedom=0,
- penalty_of_period_freedom=0,
- )
+ # Clustering Properties
+ n_clusters = 4
+ cluster_duration = '6h'
+ include_storage = False
keep_extreme_periods = True
imbalance_penalty = 1e5 # or set to None if not needed
@@ -195,12 +190,31 @@ def get_solutions(optimizations: list, variable: str) -> xr.Dataset:
optimizations.append(optimization)
if aggregated:
- if keep_extreme_periods:
- clustering_parameters.time_series_for_high_peaks = [TS_heat_demand]
- clustering_parameters.time_series_for_low_peaks = [TS_electricity_demand, TS_heat_demand]
- optimization = fx.ClusteredOptimization('Aggregated', flow_system.copy(), clustering_parameters)
- optimization.do_modeling()
- optimization.solve(fx.solvers.HighsSolver(0.01 / 100, 60))
+ # Use the new transform.cluster() API
+ # Note: time_series_for_high_peaks/low_peaks expect string labels matching dataset variables
+ time_series_for_high_peaks = ['WΓ€rmelast(Q_th_Last)|fixed_relative_profile'] if keep_extreme_periods else None
+ time_series_for_low_peaks = (
+ ['Stromlast(P_el_Last)|fixed_relative_profile', 'WΓ€rmelast(Q_th_Last)|fixed_relative_profile']
+ if keep_extreme_periods
+ else None
+ )
+
+ clustered_fs = flow_system.copy().transform.cluster(
+ n_clusters=n_clusters,
+ cluster_duration=cluster_duration,
+ time_series_for_high_peaks=time_series_for_high_peaks,
+ time_series_for_low_peaks=time_series_for_low_peaks,
+ )
+ clustered_fs.optimize(fx.solvers.HighsSolver(0.01 / 100, 60))
+
+ # Wrap in a simple object for compatibility with comparison code
+ class ClusteredResult:
+ def __init__(self, name, fs):
+ self.name = name
+ self.flow_system = fs
+ self.durations = {'total': 0} # Placeholder
+
+ optimization = ClusteredResult('Clustered', clustered_fs)
optimizations.append(optimization)
# --- Plotting for comparison ---
diff --git a/tests/deprecated/test_bus.py b/tests/deprecated/test_bus.py
index cc49a2073..9bb7ddbe3 100644
--- a/tests/deprecated/test_bus.py
+++ b/tests/deprecated/test_bus.py
@@ -74,8 +74,8 @@ def test_bus_penalty(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['TestBus->Penalty(temporal)'],
model.variables['TestBus->Penalty(temporal)']
- == model.variables['TestBus|virtual_supply'] * 1e5 * model.hours_per_step
- + model.variables['TestBus|virtual_demand'] * 1e5 * model.hours_per_step,
+ == model.variables['TestBus|virtual_supply'] * 1e5 * model.timestep_duration
+ + model.variables['TestBus|virtual_demand'] * 1e5 * model.timestep_duration,
)
def test_bus_with_coords(self, basic_flow_system_linopy_coords, coords_config):
diff --git a/tests/deprecated/test_effect.py b/tests/deprecated/test_effect.py
index b3bb278f0..1cf625c1b 100644
--- a/tests/deprecated/test_effect.py
+++ b/tests/deprecated/test_effect.py
@@ -130,8 +130,8 @@ def test_bounds(self, basic_flow_system_linopy_coords, coords_config):
assert_var_equal(
model.variables['Effect1(temporal)|per_timestep'],
model.add_variables(
- lower=4.0 * model.hours_per_step,
- upper=4.1 * model.hours_per_step,
+ lower=4.0 * model.timestep_duration,
+ upper=4.1 * model.timestep_duration,
coords=model.get_coords(['time', 'period', 'scenario']),
),
)
diff --git a/tests/deprecated/test_flow.py b/tests/deprecated/test_flow.py
index 594bc1fbb..8e1ce1f53 100644
--- a/tests/deprecated/test_flow.py
+++ b/tests/deprecated/test_flow.py
@@ -23,7 +23,7 @@ def test_flow_minimal(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|total_flow_hours'],
flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.timestep_duration).sum('time'),
)
assert_var_equal(flow.submodel.flow_rate, model.add_variables(lower=0, upper=100, coords=model.get_coords()))
assert_var_equal(
@@ -61,7 +61,7 @@ def test_flow(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|total_flow_hours'],
flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.timestep_duration).sum('time'),
)
assert_var_equal(
@@ -83,12 +83,12 @@ def test_flow(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|load_factor_min'],
- flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours'] >= model.hours_per_step.sum('time') * 0.1 * 100,
+ flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours'] >= model.timestep_duration.sum('time') * 0.1 * 100,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|load_factor_max'],
- flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours'] <= model.hours_per_step.sum('time') * 0.9 * 100,
+ flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours'] <= model.timestep_duration.sum('time') * 0.9 * 100,
)
assert_sets_equal(
@@ -129,13 +129,13 @@ def test_effects_per_flow_hour(self, basic_flow_system_linopy_coords, coords_con
assert_conequal(
model.constraints['Sink(WΓ€rme)->costs(temporal)'],
model.variables['Sink(WΓ€rme)->costs(temporal)']
- == flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.hours_per_step * costs_per_flow_hour,
+ == flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.timestep_duration * costs_per_flow_hour,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)->CO2(temporal)'],
model.variables['Sink(WΓ€rme)->CO2(temporal)']
- == flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.hours_per_step * co2_per_flow_hour,
+ == flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.timestep_duration * co2_per_flow_hour,
)
@@ -561,7 +561,7 @@ def test_flow_on(self, basic_flow_system_linopy_coords, coords_config):
model.add_variables(binary=True, coords=model.get_coords()),
)
# Upper bound is total hours when active_hours_max is not specified
- total_hours = model.hours_per_step.sum('time')
+ total_hours = model.timestep_duration.sum('time')
assert_var_equal(
model.variables['Sink(WΓ€rme)|active_hours'],
model.add_variables(lower=0, upper=total_hours, coords=model.get_coords(['period', 'scenario'])),
@@ -580,7 +580,7 @@ def test_flow_on(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|active_hours'],
flow.submodel.variables['Sink(WΓ€rme)|active_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration).sum('time'),
)
def test_effects_per_active_hour(self, basic_flow_system_linopy_coords, coords_config):
@@ -635,13 +635,13 @@ def test_effects_per_active_hour(self, basic_flow_system_linopy_coords, coords_c
assert_conequal(
model.constraints['Sink(WΓ€rme)->costs(temporal)'],
model.variables['Sink(WΓ€rme)->costs(temporal)']
- == flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step * costs_per_running_hour,
+ == flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration * costs_per_running_hour,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)->CO2(temporal)'],
model.variables['Sink(WΓ€rme)->CO2(temporal)']
- == flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step * co2_per_running_hour,
+ == flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration * co2_per_running_hour,
)
def test_consecutive_on_hours(self, basic_flow_system_linopy_coords, coords_config):
@@ -687,7 +687,7 @@ def test_consecutive_on_hours(self, basic_flow_system_linopy_coords, coords_conf
model.add_variables(lower=0, upper=8, coords=model.get_coords()),
)
- mega = model.hours_per_step.sum('time')
+ mega = model.timestep_duration.sum('time')
assert_conequal(
model.constraints['Sink(WΓ€rme)|uptime|ub'],
@@ -698,7 +698,7 @@ def test_consecutive_on_hours(self, basic_flow_system_linopy_coords, coords_conf
model.constraints['Sink(WΓ€rme)|uptime|forward'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(1, None))
<= model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1)),
+ + model.timestep_duration.isel(time=slice(None, -1)),
)
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
@@ -706,14 +706,14 @@ def test_consecutive_on_hours(self, basic_flow_system_linopy_coords, coords_conf
model.constraints['Sink(WΓ€rme)|uptime|backward'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(1, None))
>= model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1))
+ + model.timestep_duration.isel(time=slice(None, -1))
+ (model.variables['Sink(WΓ€rme)|status'].isel(time=slice(1, None)) - 1) * mega,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|uptime|initial'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=0)
- == model.variables['Sink(WΓ€rme)|status'].isel(time=0) * model.hours_per_step.isel(time=0),
+ == model.variables['Sink(WΓ€rme)|status'].isel(time=0) * model.timestep_duration.isel(time=0),
)
assert_conequal(
@@ -768,7 +768,7 @@ def test_consecutive_on_hours_previous(self, basic_flow_system_linopy_coords, co
model.add_variables(lower=0, upper=8, coords=model.get_coords()),
)
- mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 3
+ mega = model.timestep_duration.sum('time') + model.timestep_duration.isel(time=0) * 3
assert_conequal(
model.constraints['Sink(WΓ€rme)|uptime|ub'],
@@ -779,7 +779,7 @@ def test_consecutive_on_hours_previous(self, basic_flow_system_linopy_coords, co
model.constraints['Sink(WΓ€rme)|uptime|forward'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(1, None))
<= model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1)),
+ + model.timestep_duration.isel(time=slice(None, -1)),
)
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
@@ -787,14 +787,14 @@ def test_consecutive_on_hours_previous(self, basic_flow_system_linopy_coords, co
model.constraints['Sink(WΓ€rme)|uptime|backward'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(1, None))
>= model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1))
+ + model.timestep_duration.isel(time=slice(None, -1))
+ (model.variables['Sink(WΓ€rme)|status'].isel(time=slice(1, None)) - 1) * mega,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|uptime|initial'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=0)
- == model.variables['Sink(WΓ€rme)|status'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1 + 3)),
+ == model.variables['Sink(WΓ€rme)|status'].isel(time=0) * (model.timestep_duration.isel(time=0) * (1 + 3)),
)
assert_conequal(
@@ -850,7 +850,9 @@ def test_consecutive_off_hours(self, basic_flow_system_linopy_coords, coords_con
model.add_variables(lower=0, upper=12, coords=model.get_coords()),
)
- mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 1 # previously inactive for 1h
+ mega = (
+ model.timestep_duration.sum('time') + model.timestep_duration.isel(time=0) * 1
+ ) # previously inactive for 1h
assert_conequal(
model.constraints['Sink(WΓ€rme)|downtime|ub'],
@@ -861,7 +863,7 @@ def test_consecutive_off_hours(self, basic_flow_system_linopy_coords, coords_con
model.constraints['Sink(WΓ€rme)|downtime|forward'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(1, None))
<= model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1)),
+ + model.timestep_duration.isel(time=slice(None, -1)),
)
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
@@ -869,14 +871,14 @@ def test_consecutive_off_hours(self, basic_flow_system_linopy_coords, coords_con
model.constraints['Sink(WΓ€rme)|downtime|backward'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(1, None))
>= model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1))
+ + model.timestep_duration.isel(time=slice(None, -1))
+ (model.variables['Sink(WΓ€rme)|inactive'].isel(time=slice(1, None)) - 1) * mega,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|downtime|initial'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=0)
- == model.variables['Sink(WΓ€rme)|inactive'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1 + 1)),
+ == model.variables['Sink(WΓ€rme)|inactive'].isel(time=0) * (model.timestep_duration.isel(time=0) * (1 + 1)),
)
assert_conequal(
@@ -933,7 +935,7 @@ def test_consecutive_off_hours_previous(self, basic_flow_system_linopy_coords, c
model.add_variables(lower=0, upper=12, coords=model.get_coords()),
)
- mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 2
+ mega = model.timestep_duration.sum('time') + model.timestep_duration.isel(time=0) * 2
assert_conequal(
model.constraints['Sink(WΓ€rme)|downtime|ub'],
@@ -944,7 +946,7 @@ def test_consecutive_off_hours_previous(self, basic_flow_system_linopy_coords, c
model.constraints['Sink(WΓ€rme)|downtime|forward'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(1, None))
<= model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1)),
+ + model.timestep_duration.isel(time=slice(None, -1)),
)
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
@@ -952,14 +954,14 @@ def test_consecutive_off_hours_previous(self, basic_flow_system_linopy_coords, c
model.constraints['Sink(WΓ€rme)|downtime|backward'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(1, None))
>= model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1))
+ + model.timestep_duration.isel(time=slice(None, -1))
+ (model.variables['Sink(WΓ€rme)|inactive'].isel(time=slice(1, None)) - 1) * mega,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|downtime|initial'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=0)
- == model.variables['Sink(WΓ€rme)|inactive'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1 + 2)),
+ == model.variables['Sink(WΓ€rme)|inactive'].isel(time=0) * (model.timestep_duration.isel(time=0) * (1 + 2)),
)
assert_conequal(
@@ -1067,7 +1069,7 @@ def test_on_hours_limits(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|active_hours'],
flow.submodel.variables['Sink(WΓ€rme)|active_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration).sum('time'),
)
@@ -1131,7 +1133,7 @@ def test_flow_on_invest_optional(self, basic_flow_system_linopy_coords, coords_c
model.add_variables(binary=True, coords=model.get_coords()),
)
# Upper bound is total hours when active_hours_max is not specified
- total_hours = model.hours_per_step.sum('time')
+ total_hours = model.timestep_duration.sum('time')
assert_var_equal(
model.variables['Sink(WΓ€rme)|active_hours'],
model.add_variables(lower=0, upper=total_hours, coords=model.get_coords(['period', 'scenario'])),
@@ -1157,7 +1159,7 @@ def test_flow_on_invest_optional(self, basic_flow_system_linopy_coords, coords_c
assert_conequal(
model.constraints['Sink(WΓ€rme)|active_hours'],
flow.submodel.variables['Sink(WΓ€rme)|active_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration).sum('time'),
)
# Investment
@@ -1233,7 +1235,7 @@ def test_flow_on_invest_non_optional(self, basic_flow_system_linopy_coords, coor
model.add_variables(binary=True, coords=model.get_coords()),
)
# Upper bound is total hours when active_hours_max is not specified
- total_hours = model.hours_per_step.sum('time')
+ total_hours = model.timestep_duration.sum('time')
assert_var_equal(
model.variables['Sink(WΓ€rme)|active_hours'],
model.add_variables(lower=0, upper=total_hours, coords=model.get_coords(['period', 'scenario'])),
@@ -1251,7 +1253,7 @@ def test_flow_on_invest_non_optional(self, basic_flow_system_linopy_coords, coor
assert_conequal(
model.constraints['Sink(WΓ€rme)|active_hours'],
flow.submodel.variables['Sink(WΓ€rme)|active_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration).sum('time'),
)
# Investment
diff --git a/tests/deprecated/test_flow_system_resample.py b/tests/deprecated/test_flow_system_resample.py
index c76946f80..549f05208 100644
--- a/tests/deprecated/test_flow_system_resample.py
+++ b/tests/deprecated/test_flow_system_resample.py
@@ -128,7 +128,7 @@ def test_time_metadata_updated(simple_fs):
"""Test time metadata correctly updated."""
fs_r = simple_fs.resample('3h', method='mean')
assert len(fs_r.timesteps) == 8
- assert_allclose(fs_r.hours_per_timestep.values, 3.0)
+ assert_allclose(fs_r.timestep_duration.values, 3.0)
assert fs_r.hours_of_last_timestep == 3.0
diff --git a/tests/deprecated/test_integration.py b/tests/deprecated/test_integration.py
index 2f083b4fb..8ec23265e 100644
--- a/tests/deprecated/test_integration.py
+++ b/tests/deprecated/test_integration.py
@@ -258,15 +258,15 @@ def test_piecewise_conversion(self, flow_system_piecewise_conversion, highs_solv
@pytest.mark.slow
class TestModelingTypes:
- @pytest.fixture(params=['full', 'segmented', 'aggregated'])
+ # Note: 'aggregated' case removed - ClusteredOptimization has been replaced by
+ # FlowSystem.transform.cluster(). See tests/test_clustering/ for new clustering tests.
+ @pytest.fixture(params=['full', 'segmented'])
def modeling_calculation(self, request, flow_system_long, highs_solver):
"""
Fixture to run optimizations with different modeling types
"""
# Extract flow system and data from the fixture
flow_system = flow_system_long[0]
- thermal_load_ts = flow_system_long[1]['thermal_load_ts']
- electrical_load_ts = flow_system_long[1]['electrical_load_ts']
# Create calculation based on modeling type
modeling_type = request.param
@@ -277,23 +277,6 @@ def modeling_calculation(self, request, flow_system_long, highs_solver):
elif modeling_type == 'segmented':
calc = fx.SegmentedOptimization('segModel', flow_system, timesteps_per_segment=96, overlap_timesteps=1)
calc.do_modeling_and_solve(highs_solver)
- elif modeling_type == 'aggregated':
- calc = fx.ClusteredOptimization(
- 'aggModel',
- flow_system,
- fx.ClusteringParameters(
- hours_per_period=6,
- nr_of_periods=4,
- fix_storage_flows=False,
- aggregate_data_and_fix_non_binary_vars=True,
- percentage_of_period_freedom=0,
- penalty_of_period_freedom=0,
- time_series_for_low_peaks=[electrical_load_ts, thermal_load_ts],
- time_series_for_high_peaks=[thermal_load_ts],
- ),
- )
- calc.do_modeling()
- calc.solve(highs_solver)
return calc, modeling_type
@@ -306,16 +289,15 @@ def test_modeling_types_costs(self, modeling_calculation):
expected_costs = {
'full': 343613,
'segmented': 343613, # Approximate value
- 'aggregated': 342967.0,
}
- if modeling_type in ['full', 'aggregated']:
+ if modeling_type == 'full':
assert_almost_equal_numeric(
calc.results.model['costs'].solution.item(),
expected_costs[modeling_type],
f'costs do not match for {modeling_type} modeling type',
)
- else:
+ elif modeling_type == 'segmented':
assert_almost_equal_numeric(
calc.results.solution_without_overlap('costs(temporal)|per_timestep').sum(),
expected_costs[modeling_type],
diff --git a/tests/deprecated/test_linear_converter.py b/tests/deprecated/test_linear_converter.py
index 57b911d64..d20d104d0 100644
--- a/tests/deprecated/test_linear_converter.py
+++ b/tests/deprecated/test_linear_converter.py
@@ -174,7 +174,7 @@ def test_linear_converter_with_status(self, basic_flow_system_linopy_coords, coo
assert_conequal(
model.constraints['Converter|active_hours'],
model.variables['Converter|active_hours']
- == (model.variables['Converter|status'] * model.hours_per_step).sum('time'),
+ == (model.variables['Converter|status'] * model.timestep_duration).sum('time'),
)
# Check conversion constraint
@@ -188,7 +188,7 @@ def test_linear_converter_with_status(self, basic_flow_system_linopy_coords, coo
assert_conequal(
model.constraints['Converter->costs(temporal)'],
model.variables['Converter->costs(temporal)']
- == model.variables['Converter|status'] * model.hours_per_step * 5,
+ == model.variables['Converter|status'] * model.timestep_duration * 5,
)
def test_linear_converter_multidimensional(self, basic_flow_system_linopy_coords, coords_config):
@@ -485,7 +485,7 @@ def test_piecewise_conversion_with_status(self, basic_flow_system_linopy_coords,
assert 'Converter|active_hours' in model.constraints
assert_conequal(
model.constraints['Converter|active_hours'],
- model['Converter|active_hours'] == (model['Converter|status'] * model.hours_per_step).sum('time'),
+ model['Converter|active_hours'] == (model['Converter|status'] * model.timestep_duration).sum('time'),
)
# Verify that the costs effect is applied
@@ -493,7 +493,7 @@ def test_piecewise_conversion_with_status(self, basic_flow_system_linopy_coords,
assert_conequal(
model.constraints['Converter->costs(temporal)'],
model.variables['Converter->costs(temporal)']
- == model.variables['Converter|status'] * model.hours_per_step * 5,
+ == model.variables['Converter|status'] * model.timestep_duration * 5,
)
diff --git a/tests/deprecated/test_on_hours_computation.py b/tests/deprecated/test_on_hours_computation.py
index 578fd7792..c74332565 100644
--- a/tests/deprecated/test_on_hours_computation.py
+++ b/tests/deprecated/test_on_hours_computation.py
@@ -9,7 +9,7 @@ class TestComputeConsecutiveDuration:
"""Tests for the compute_consecutive_hours_in_state static method."""
@pytest.mark.parametrize(
- 'binary_values, hours_per_timestep, expected',
+ 'binary_values, timestep_duration, expected',
[
# Case 1: Single timestep DataArrays
(xr.DataArray([1], dims=['time']), 5, 5),
@@ -26,22 +26,22 @@ class TestComputeConsecutiveDuration:
(xr.DataArray([0, 1, 1, 1, 0, 0], dims=['time']), 1, 0), # ends with 0
],
)
- def test_compute_duration(self, binary_values, hours_per_timestep, expected):
+ def test_compute_duration(self, binary_values, timestep_duration, expected):
"""Test compute_consecutive_hours_in_state with various inputs."""
- result = ModelingUtilities.compute_consecutive_hours_in_state(binary_values, hours_per_timestep)
+ result = ModelingUtilities.compute_consecutive_hours_in_state(binary_values, timestep_duration)
assert np.isclose(result, expected)
@pytest.mark.parametrize(
- 'binary_values, hours_per_timestep',
+ 'binary_values, timestep_duration',
[
- # Case: hours_per_timestep must be scalar
+ # Case: timestep_duration must be scalar
(xr.DataArray([1, 1, 1, 1, 1], dims=['time']), np.array([1, 2])),
],
)
- def test_compute_duration_raises_error(self, binary_values, hours_per_timestep):
+ def test_compute_duration_raises_error(self, binary_values, timestep_duration):
"""Test error conditions."""
with pytest.raises(TypeError):
- ModelingUtilities.compute_consecutive_hours_in_state(binary_values, hours_per_timestep)
+ ModelingUtilities.compute_consecutive_hours_in_state(binary_values, timestep_duration)
class TestComputePreviousOnStates:
diff --git a/tests/deprecated/test_scenarios.py b/tests/deprecated/test_scenarios.py
index 65ea62d81..2699647ad 100644
--- a/tests/deprecated/test_scenarios.py
+++ b/tests/deprecated/test_scenarios.py
@@ -341,12 +341,14 @@ def test_scenarios_selection(flow_system_piecewise_conversion_scenarios):
assert flow_system.scenarios.equals(flow_system_full.scenarios[0:2])
- np.testing.assert_allclose(flow_system.scenario_weights.values, flow_system_full.scenario_weights[0:2])
+ # Scenario weights are always normalized - subset is re-normalized to sum to 1
+ subset_weights = flow_system_full.scenario_weights[0:2]
+ expected_normalized = subset_weights / subset_weights.sum()
+ np.testing.assert_allclose(flow_system.scenario_weights.values, expected_normalized.values)
- # Optimize using new API with normalize_weights=False
+ # Optimize using new API
flow_system.optimize(
fx.solvers.GurobiSolver(mip_gap=0.01, time_limit_seconds=60),
- normalize_weights=False,
)
# Penalty has same structure as other effects: 'Penalty' is the total, 'Penalty(temporal)' and 'Penalty(periodic)' are components
@@ -769,7 +771,10 @@ def test_weights_selection():
# Verify weights are correctly sliced
assert fs_subset.scenarios.equals(pd.Index(['base', 'high'], name='scenario'))
- np.testing.assert_allclose(fs_subset.scenario_weights.values, custom_scenario_weights[[0, 2]])
+ # Scenario weights are always normalized - subset is re-normalized to sum to 1
+ subset_weights = np.array([0.3, 0.2]) # Original weights for selected scenarios
+ expected_normalized = subset_weights / subset_weights.sum()
+ np.testing.assert_allclose(fs_subset.scenario_weights.values, expected_normalized)
# Verify weights are 1D with just scenario dimension (no period dimension)
assert fs_subset.scenario_weights.dims == ('scenario',)
diff --git a/tests/deprecated/test_storage.py b/tests/deprecated/test_storage.py
index 15170a321..3fd47fbf8 100644
--- a/tests/deprecated/test_storage.py
+++ b/tests/deprecated/test_storage.py
@@ -73,8 +73,8 @@ def test_basic_storage(self, basic_flow_system_linopy_coords, coords_config):
model.constraints['TestStorage|charge_state'],
charge_state.isel(time=slice(1, None))
== charge_state.isel(time=slice(None, -1))
- + model.variables['TestStorage(Q_th_in)|flow_rate'] * model.hours_per_step
- - model.variables['TestStorage(Q_th_out)|flow_rate'] * model.hours_per_step,
+ + model.variables['TestStorage(Q_th_in)|flow_rate'] * model.timestep_duration
+ - model.variables['TestStorage(Q_th_out)|flow_rate'] * model.timestep_duration,
)
# Check initial charge state constraint
assert_conequal(
@@ -146,7 +146,7 @@ def test_lossy_storage(self, basic_flow_system_linopy_coords, coords_config):
charge_state = model.variables['TestStorage|charge_state']
rel_loss = 0.05
- hours_per_step = model.hours_per_step
+ timestep_duration = model.timestep_duration
charge_rate = model.variables['TestStorage(Q_th_in)|flow_rate']
discharge_rate = model.variables['TestStorage(Q_th_out)|flow_rate']
eff_charge = 0.9
@@ -155,9 +155,9 @@ def test_lossy_storage(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['TestStorage|charge_state'],
charge_state.isel(time=slice(1, None))
- == charge_state.isel(time=slice(None, -1)) * (1 - rel_loss) ** hours_per_step
- + charge_rate * eff_charge * hours_per_step
- - discharge_rate / eff_discharge * hours_per_step,
+ == charge_state.isel(time=slice(None, -1)) * (1 - rel_loss) ** timestep_duration
+ + charge_rate * eff_charge * timestep_duration
+ - discharge_rate / eff_discharge * timestep_duration,
)
# Check initial charge state constraint
@@ -242,8 +242,8 @@ def test_charge_state_bounds(self, basic_flow_system_linopy_coords, coords_confi
model.constraints['TestStorage|charge_state'],
charge_state.isel(time=slice(1, None))
== charge_state.isel(time=slice(None, -1))
- + model.variables['TestStorage(Q_th_in)|flow_rate'] * model.hours_per_step
- - model.variables['TestStorage(Q_th_out)|flow_rate'] * model.hours_per_step,
+ + model.variables['TestStorage(Q_th_in)|flow_rate'] * model.timestep_duration
+ - model.variables['TestStorage(Q_th_out)|flow_rate'] * model.timestep_duration,
)
# Check initial charge state constraint
assert_conequal(
diff --git a/tests/test_bus.py b/tests/test_bus.py
index cc49a2073..9bb7ddbe3 100644
--- a/tests/test_bus.py
+++ b/tests/test_bus.py
@@ -74,8 +74,8 @@ def test_bus_penalty(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['TestBus->Penalty(temporal)'],
model.variables['TestBus->Penalty(temporal)']
- == model.variables['TestBus|virtual_supply'] * 1e5 * model.hours_per_step
- + model.variables['TestBus|virtual_demand'] * 1e5 * model.hours_per_step,
+ == model.variables['TestBus|virtual_supply'] * 1e5 * model.timestep_duration
+ + model.variables['TestBus|virtual_demand'] * 1e5 * model.timestep_duration,
)
def test_bus_with_coords(self, basic_flow_system_linopy_coords, coords_config):
diff --git a/tests/test_cluster_reduce_expand.py b/tests/test_cluster_reduce_expand.py
new file mode 100644
index 000000000..4059470ee
--- /dev/null
+++ b/tests/test_cluster_reduce_expand.py
@@ -0,0 +1,836 @@
+"""Tests for cluster() and expand_solution() functionality."""
+
+import numpy as np
+import pandas as pd
+import pytest
+from numpy.testing import assert_allclose
+
+import flixopt as fx
+
+
+def create_simple_system(timesteps: pd.DatetimeIndex) -> fx.FlowSystem:
+ """Create a simple FlowSystem for testing clustering."""
+ # Create varying demand - different for each day to test clustering
+ hours = len(timesteps)
+ demand = np.sin(np.linspace(0, 4 * np.pi, hours)) * 10 + 15 # Oscillating demand
+
+ flow_system = fx.FlowSystem(timesteps)
+ flow_system.add_elements(
+ fx.Bus('Heat'),
+ fx.Bus('Gas'),
+ fx.Effect('costs', 'β¬', is_standard=True, is_objective=True),
+ fx.Sink('HeatDemand', inputs=[fx.Flow('Q', bus='Heat', fixed_relative_profile=demand, size=1)]),
+ fx.Source('GasSource', outputs=[fx.Flow('Gas', bus='Gas', effects_per_flow_hour=0.05)]),
+ fx.linear_converters.Boiler(
+ 'Boiler',
+ thermal_efficiency=0.9,
+ fuel_flow=fx.Flow('Q_fu', bus='Gas'),
+ thermal_flow=fx.Flow('Q_th', bus='Heat'),
+ ),
+ )
+ return flow_system
+
+
+@pytest.fixture
+def timesteps_2_days():
+ """48 hour timesteps (2 days)."""
+ return pd.date_range('2020-01-01', periods=48, freq='h')
+
+
+@pytest.fixture
+def timesteps_8_days():
+ """192 hour timesteps (8 days) - more realistic for clustering."""
+ return pd.date_range('2020-01-01', periods=192, freq='h')
+
+
+def test_cluster_creates_reduced_timesteps(timesteps_8_days):
+ """Test that cluster creates a FlowSystem with fewer timesteps."""
+ fs = create_simple_system(timesteps_8_days)
+
+ # Reduce to 2 typical clusters (days)
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+
+ # Clustered FlowSystem has 2D structure: (cluster, time)
+ # - timesteps: within-cluster time (24 hours)
+ # - clusters: cluster indices (2 clusters)
+ # Total effective timesteps = 2 * 24 = 48
+ assert len(fs_reduced.timesteps) == 24 # Within-cluster time
+ assert len(fs_reduced.clusters) == 2 # Number of clusters
+ assert len(fs_reduced.timesteps) * len(fs_reduced.clusters) == 48 # Total
+ assert hasattr(fs_reduced, 'clustering')
+ assert fs_reduced.clustering.result.cluster_structure.n_clusters == 2
+
+
+def test_expand_solution_restores_full_timesteps(solver_fixture, timesteps_8_days):
+ """Test that expand_solution restores full timestep count."""
+ fs = create_simple_system(timesteps_8_days)
+
+ # Reduce to 2 typical clusters
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+
+ # Optimize
+ fs_reduced.optimize(solver_fixture)
+ assert fs_reduced.solution is not None
+ # Clustered: 24 within-cluster timesteps, 2 clusters
+ assert len(fs_reduced.timesteps) == 24
+ assert len(fs_reduced.clusters) == 2
+
+ # Expand back to full
+ fs_expanded = fs_reduced.transform.expand_solution()
+
+ # Should have original timestep count (flat, no clusters)
+ assert len(fs_expanded.timesteps) == 192
+ assert fs_expanded.clusters is None # Expanded FlowSystem has no cluster dimension
+ assert fs_expanded.solution is not None
+
+
+def test_expand_solution_preserves_solution_variables(solver_fixture, timesteps_8_days):
+ """Test that expand_solution keeps all solution variables."""
+ fs = create_simple_system(timesteps_8_days)
+
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+ fs_reduced.optimize(solver_fixture)
+
+ reduced_vars = set(fs_reduced.solution.data_vars)
+
+ fs_expanded = fs_reduced.transform.expand_solution()
+ expanded_vars = set(fs_expanded.solution.data_vars)
+
+ # Should have all the same variables
+ assert reduced_vars == expanded_vars
+
+
+def test_expand_solution_maps_values_correctly(solver_fixture, timesteps_8_days):
+ """Test that expand_solution correctly maps typical cluster values to all segments."""
+ fs = create_simple_system(timesteps_8_days)
+
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+ fs_reduced.optimize(solver_fixture)
+
+ # Get cluster_order to know mapping
+ info = fs_reduced.clustering
+ cluster_order = info.result.cluster_structure.cluster_order.values
+ timesteps_per_cluster = info.result.cluster_structure.timesteps_per_cluster # 24
+
+ reduced_flow = fs_reduced.solution['Boiler(Q_th)|flow_rate'].values
+
+ fs_expanded = fs_reduced.transform.expand_solution()
+ expanded_flow = fs_expanded.solution['Boiler(Q_th)|flow_rate'].values
+
+ # Check that values are correctly mapped
+ # For each original segment, values should match the corresponding typical cluster
+ for orig_segment_idx, cluster_id in enumerate(cluster_order):
+ orig_start = orig_segment_idx * timesteps_per_cluster
+ orig_end = orig_start + timesteps_per_cluster
+
+ # Values in the expanded solution for this original segment
+ # should match the reduced solution for the corresponding typical cluster
+ # With 2D cluster structure, use cluster_id to index the cluster dimension
+ # Note: solution may have extra timesteps (timesteps_extra), so slice to timesteps_per_cluster
+ if reduced_flow.ndim == 2:
+ # 2D structure: (cluster, time) - exclude extra timestep if present
+ expected = reduced_flow[cluster_id, :timesteps_per_cluster]
+ else:
+ # Flat structure: (time,)
+ typical_start = cluster_id * timesteps_per_cluster
+ typical_end = typical_start + timesteps_per_cluster
+ expected = reduced_flow[typical_start:typical_end]
+ actual = expanded_flow[orig_start:orig_end]
+
+ assert_allclose(actual, expected, rtol=1e-10)
+
+
+def test_expand_solution_enables_statistics_accessor(solver_fixture, timesteps_8_days):
+ """Test that statistics accessor works on expanded FlowSystem."""
+ fs = create_simple_system(timesteps_8_days)
+
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+ fs_reduced.optimize(solver_fixture)
+
+ fs_expanded = fs_reduced.transform.expand_solution()
+
+ # These should work without errors
+ flow_rates = fs_expanded.statistics.flow_rates
+ assert 'Boiler(Q_th)' in flow_rates
+ assert len(flow_rates['Boiler(Q_th)'].coords['time']) == 193 # 192 + 1 extra timestep
+
+ flow_hours = fs_expanded.statistics.flow_hours
+ assert 'Boiler(Q_th)' in flow_hours
+
+
+def test_expand_solution_statistics_match_clustered(solver_fixture, timesteps_8_days):
+ """Test that total_effects match between clustered and expanded FlowSystem."""
+ fs = create_simple_system(timesteps_8_days)
+
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+ fs_reduced.optimize(solver_fixture)
+
+ fs_expanded = fs_reduced.transform.expand_solution()
+
+ # Total effects should match between clustered and expanded
+ reduced_total = fs_reduced.statistics.total_effects['costs'].sum('contributor').item()
+ expanded_total = fs_expanded.statistics.total_effects['costs'].sum('contributor').item()
+
+ assert_allclose(reduced_total, expanded_total, rtol=1e-6)
+
+ # Flow hours should also match (need to sum over time with proper weighting)
+ # With 2D cluster structure, sum over both cluster and time dimensions
+ reduced_fh = fs_reduced.statistics.flow_hours['Boiler(Q_th)'] * fs_reduced.cluster_weight
+ reduced_flow_hours = reduced_fh.sum().item() # Sum over all dimensions
+ expanded_fh = fs_expanded.statistics.flow_hours['Boiler(Q_th)'] * fs_expanded.cluster_weight
+ expanded_flow_hours = expanded_fh.sum().item()
+
+ assert_allclose(reduced_flow_hours, expanded_flow_hours, rtol=1e-6)
+
+
+def test_expand_solution_withoutclustering_raises(solver_fixture, timesteps_2_days):
+ """Test that expand_solution raises error if not a reduced FlowSystem."""
+ fs = create_simple_system(timesteps_2_days)
+ fs.optimize(solver_fixture)
+
+ with pytest.raises(ValueError, match='cluster'):
+ fs.transform.expand_solution()
+
+
+def test_expand_solution_without_solution_raises(timesteps_8_days):
+ """Test that expand_solution raises error if no solution."""
+ fs = create_simple_system(timesteps_8_days)
+
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+ # Don't optimize - no solution
+
+ with pytest.raises(ValueError, match='no solution'):
+ fs_reduced.transform.expand_solution()
+
+
+# ==================== Multi-dimensional Tests ====================
+
+
+def create_system_with_scenarios(timesteps: pd.DatetimeIndex, scenarios: pd.Index) -> fx.FlowSystem:
+ """Create a FlowSystem with scenarios for testing."""
+ hours = len(timesteps)
+
+ # Create different demand profiles per scenario
+ demands = {}
+ for i, scenario in enumerate(scenarios):
+ # Different pattern per scenario
+ base_demand = np.sin(np.linspace(0, 4 * np.pi, hours)) * 10 + 15
+ demands[scenario] = base_demand * (1 + 0.2 * i) # Scale differently per scenario
+
+ # Create DataFrame with scenarios as columns
+ demand_df = pd.DataFrame(demands, index=timesteps)
+
+ flow_system = fx.FlowSystem(timesteps, scenarios=scenarios)
+ flow_system.add_elements(
+ fx.Bus('Heat'),
+ fx.Bus('Gas'),
+ fx.Effect('costs', 'β¬', is_standard=True, is_objective=True),
+ fx.Sink(
+ 'HeatDemand',
+ inputs=[fx.Flow('Q', bus='Heat', fixed_relative_profile=demand_df, size=1)],
+ ),
+ fx.Source('GasSource', outputs=[fx.Flow('Gas', bus='Gas', effects_per_flow_hour=0.05)]),
+ fx.linear_converters.Boiler(
+ 'Boiler',
+ thermal_efficiency=0.9,
+ fuel_flow=fx.Flow('Q_fu', bus='Gas'),
+ thermal_flow=fx.Flow('Q_th', bus='Heat'),
+ ),
+ )
+ return flow_system
+
+
+@pytest.fixture
+def scenarios_2():
+ """Two scenarios for testing."""
+ return pd.Index(['base', 'high'], name='scenario')
+
+
+def test_cluster_with_scenarios(timesteps_8_days, scenarios_2):
+ """Test that cluster handles scenarios correctly."""
+ fs = create_system_with_scenarios(timesteps_8_days, scenarios_2)
+
+ # Verify scenarios are set up correctly
+ assert fs.scenarios is not None
+ assert len(fs.scenarios) == 2
+
+ # Reduce to 2 typical clusters
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+
+ # Clustered: 24 within-cluster timesteps, 2 clusters
+ # Total effective timesteps = 2 * 24 = 48
+ assert len(fs_reduced.timesteps) == 24
+ assert len(fs_reduced.clusters) == 2
+ assert len(fs_reduced.timesteps) * len(fs_reduced.clusters) == 48
+
+ # Should have aggregation info with cluster structure
+ info = fs_reduced.clustering
+ assert info is not None
+ assert info.result.cluster_structure is not None
+ assert info.result.cluster_structure.n_clusters == 2
+ # Clustered FlowSystem preserves scenarios
+ assert fs_reduced.scenarios is not None
+ assert len(fs_reduced.scenarios) == 2
+
+
+def test_cluster_and_expand_with_scenarios(solver_fixture, timesteps_8_days, scenarios_2):
+ """Test full cluster -> optimize -> expand_solution cycle with scenarios."""
+ fs = create_system_with_scenarios(timesteps_8_days, scenarios_2)
+
+ # Reduce
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+
+ # Optimize
+ fs_reduced.optimize(solver_fixture)
+ assert fs_reduced.solution is not None
+
+ # Expand
+ fs_expanded = fs_reduced.transform.expand_solution()
+
+ # Should have original timesteps
+ assert len(fs_expanded.timesteps) == 192
+
+ # Solution should have scenario dimension
+ flow_var = 'Boiler(Q_th)|flow_rate'
+ assert flow_var in fs_expanded.solution
+ assert 'scenario' in fs_expanded.solution[flow_var].dims
+ assert len(fs_expanded.solution[flow_var].coords['time']) == 193 # 192 + 1 extra timestep
+
+
+def test_expand_solution_maps_scenarios_independently(solver_fixture, timesteps_8_days, scenarios_2):
+ """Test that expand_solution correctly maps scenarios in multi-scenario systems."""
+ fs = create_system_with_scenarios(timesteps_8_days, scenarios_2)
+
+ fs_reduced = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+ fs_reduced.optimize(solver_fixture)
+
+ info = fs_reduced.clustering
+ cluster_structure = info.result.cluster_structure
+ timesteps_per_cluster = cluster_structure.timesteps_per_cluster # 24
+
+ reduced_flow = fs_reduced.solution['Boiler(Q_th)|flow_rate']
+ fs_expanded = fs_reduced.transform.expand_solution()
+ expanded_flow = fs_expanded.solution['Boiler(Q_th)|flow_rate']
+
+ # Check mapping for each scenario using its own cluster_order
+ for scenario in scenarios_2:
+ # Get the cluster_order for THIS scenario
+ cluster_order = cluster_structure.get_cluster_order_for_slice(scenario=scenario)
+
+ reduced_scenario = reduced_flow.sel(scenario=scenario).values
+ expanded_scenario = expanded_flow.sel(scenario=scenario).values
+
+ # Verify mapping is correct for this scenario using its own cluster_order
+ for orig_segment_idx, cluster_id in enumerate(cluster_order):
+ orig_start = orig_segment_idx * timesteps_per_cluster
+ orig_end = orig_start + timesteps_per_cluster
+
+ # With 2D cluster structure, use cluster_id to index the cluster dimension
+ # Note: solution may have extra timesteps (timesteps_extra), so slice to timesteps_per_cluster
+ if reduced_scenario.ndim == 2:
+ # 2D structure: (cluster, time) - exclude extra timestep if present
+ expected = reduced_scenario[cluster_id, :timesteps_per_cluster]
+ else:
+ # Flat structure: (time,)
+ typical_start = cluster_id * timesteps_per_cluster
+ typical_end = typical_start + timesteps_per_cluster
+ expected = reduced_scenario[typical_start:typical_end]
+ actual = expanded_scenario[orig_start:orig_end]
+
+ assert_allclose(actual, expected, rtol=1e-10, err_msg=f'Mismatch for scenario {scenario}')
+
+
+# ==================== Storage Clustering Tests ====================
+
+
+def create_system_with_storage(
+ timesteps: pd.DatetimeIndex,
+ cluster_mode: str = 'intercluster_cyclic',
+ relative_loss_per_hour: float = 0.0,
+) -> fx.FlowSystem:
+ """Create a FlowSystem with storage for testing clustering.
+
+ Args:
+ timesteps: DatetimeIndex for the simulation.
+ cluster_mode: Storage cluster mode ('independent', 'cyclic', 'intercluster', 'intercluster_cyclic').
+ relative_loss_per_hour: Self-discharge rate per hour (0.0 = no loss).
+ """
+ # Create demand pattern: high during day (hours 8-18), low at night
+ hour_of_day = np.array([t.hour for t in timesteps])
+ demand = np.where((hour_of_day >= 8) & (hour_of_day < 18), 20, 5)
+
+ flow_system = fx.FlowSystem(timesteps)
+ flow_system.add_elements(
+ fx.Bus('Elec'),
+ fx.Effect('costs', 'β¬', is_standard=True, is_objective=True),
+ fx.Source('Grid', outputs=[fx.Flow('P', bus='Elec', size=100, effects_per_flow_hour=0.1)]),
+ fx.Sink('Load', inputs=[fx.Flow('P', bus='Elec', fixed_relative_profile=demand, size=1)]),
+ fx.Storage(
+ 'Battery',
+ charging=fx.Flow('charge', bus='Elec', size=30),
+ discharging=fx.Flow('discharge', bus='Elec', size=30),
+ capacity_in_flow_hours=100,
+ relative_loss_per_hour=relative_loss_per_hour,
+ cluster_mode=cluster_mode,
+ ),
+ )
+ return flow_system
+
+
+class TestStorageClusterModes:
+ """Tests for different storage cluster_mode options."""
+
+ def test_storage_cluster_mode_independent(self, solver_fixture, timesteps_8_days):
+ """Storage with cluster_mode='independent' - each cluster starts fresh."""
+ fs = create_system_with_storage(timesteps_8_days, cluster_mode='independent')
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Should have charge_state in solution
+ assert 'Battery|charge_state' in fs_clustered.solution
+
+ # Independent mode should NOT have SOC_boundary
+ assert 'Battery|SOC_boundary' not in fs_clustered.solution
+
+ # Verify solution is valid (no errors)
+ assert fs_clustered.solution is not None
+
+ def test_storage_cluster_mode_cyclic(self, solver_fixture, timesteps_8_days):
+ """Storage with cluster_mode='cyclic' - start equals end per cluster."""
+ fs = create_system_with_storage(timesteps_8_days, cluster_mode='cyclic')
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Should have charge_state in solution
+ assert 'Battery|charge_state' in fs_clustered.solution
+
+ # Cyclic mode should NOT have SOC_boundary (only intercluster modes do)
+ assert 'Battery|SOC_boundary' not in fs_clustered.solution
+
+ def test_storage_cluster_mode_intercluster(self, solver_fixture, timesteps_8_days):
+ """Storage with cluster_mode='intercluster' - SOC links across clusters."""
+ fs = create_system_with_storage(timesteps_8_days, cluster_mode='intercluster')
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Intercluster mode SHOULD have SOC_boundary
+ assert 'Battery|SOC_boundary' in fs_clustered.solution
+
+ soc_boundary = fs_clustered.solution['Battery|SOC_boundary']
+ assert 'cluster_boundary' in soc_boundary.dims
+
+ # Number of boundaries = n_original_clusters + 1
+ n_original_clusters = fs_clustered.clustering.result.cluster_structure.n_original_clusters
+ assert soc_boundary.sizes['cluster_boundary'] == n_original_clusters + 1
+
+ def test_storage_cluster_mode_intercluster_cyclic(self, solver_fixture, timesteps_8_days):
+ """Storage with cluster_mode='intercluster_cyclic' - linked with yearly cycling."""
+ fs = create_system_with_storage(timesteps_8_days, cluster_mode='intercluster_cyclic')
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Intercluster_cyclic mode SHOULD have SOC_boundary
+ assert 'Battery|SOC_boundary' in fs_clustered.solution
+
+ soc_boundary = fs_clustered.solution['Battery|SOC_boundary']
+ assert 'cluster_boundary' in soc_boundary.dims
+
+ # First and last SOC_boundary values should be equal (cyclic constraint)
+ first_soc = soc_boundary.isel(cluster_boundary=0).item()
+ last_soc = soc_boundary.isel(cluster_boundary=-1).item()
+ assert_allclose(first_soc, last_soc, rtol=1e-6)
+
+
+class TestInterclusterStorageLinking:
+ """Tests for inter-cluster storage linking and SOC_boundary behavior."""
+
+ def test_intercluster_storage_has_soc_boundary(self, solver_fixture, timesteps_8_days):
+ """Verify intercluster storage creates SOC_boundary variable."""
+ fs = create_system_with_storage(timesteps_8_days, cluster_mode='intercluster_cyclic')
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Verify SOC_boundary exists in solution
+ assert 'Battery|SOC_boundary' in fs_clustered.solution
+ soc_boundary = fs_clustered.solution['Battery|SOC_boundary']
+ assert 'cluster_boundary' in soc_boundary.dims
+
+ def test_expand_solution_combines_soc_boundary_with_charge_state(self, solver_fixture, timesteps_8_days):
+ """Expanded charge_state should be non-negative (combined with SOC_boundary)."""
+ fs = create_system_with_storage(timesteps_8_days, cluster_mode='intercluster_cyclic')
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Note: Before expansion, charge_state represents ΞE (relative to period start)
+ # which can be negative. After expansion, it becomes absolute SOC.
+
+ # After expansion: charge_state should be non-negative (absolute SOC)
+ fs_expanded = fs_clustered.transform.expand_solution()
+ cs_after = fs_expanded.solution['Battery|charge_state']
+
+ # All values should be >= 0 (with small tolerance for numerical issues)
+ assert (cs_after >= -0.01).all(), f'Negative charge_state found: min={float(cs_after.min())}'
+
+ def test_storage_self_discharge_decay_in_expansion(self, solver_fixture, timesteps_8_days):
+ """Verify self-discharge decay factor applied correctly during expansion."""
+ # Use significant self-discharge to make decay visible
+ fs = create_system_with_storage(
+ timesteps_8_days,
+ cluster_mode='intercluster_cyclic',
+ relative_loss_per_hour=0.01, # 1% per hour
+ )
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Expand solution
+ fs_expanded = fs_clustered.transform.expand_solution()
+ cs_expanded = fs_expanded.solution['Battery|charge_state']
+
+ # With self-discharge, SOC should decay over time within each period
+ # The expanded solution should still be non-negative
+ assert (cs_expanded >= -0.01).all()
+
+ def test_expanded_charge_state_matches_manual_calculation(self, solver_fixture, timesteps_8_days):
+ """Verify expanded charge_state = SOC_boundary * decay + delta_E formula."""
+ loss_rate = 0.01 # 1% per hour
+ fs = create_system_with_storage(
+ timesteps_8_days,
+ cluster_mode='intercluster_cyclic',
+ relative_loss_per_hour=loss_rate,
+ )
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Get values needed for manual calculation
+ soc_boundary = fs_clustered.solution['Battery|SOC_boundary']
+ cs_clustered = fs_clustered.solution['Battery|charge_state']
+ cluster_structure = fs_clustered.clustering.result.cluster_structure
+ cluster_order = cluster_structure.cluster_order.values
+ timesteps_per_cluster = cluster_structure.timesteps_per_cluster
+
+ fs_expanded = fs_clustered.transform.expand_solution()
+ cs_expanded = fs_expanded.solution['Battery|charge_state']
+
+ # Manual verification for first few timesteps of first period
+ p = 0 # First period
+ cluster = int(cluster_order[p])
+ soc_b = soc_boundary.isel(cluster_boundary=p).item()
+
+ for t in [0, 5, 12, 23]:
+ global_t = p * timesteps_per_cluster + t
+ delta_e = cs_clustered.isel(cluster=cluster, time=t).item()
+ decay = (1 - loss_rate) ** t
+ expected = soc_b * decay + delta_e
+ expected_clipped = max(0.0, expected)
+ actual = cs_expanded.isel(time=global_t).item()
+
+ assert_allclose(
+ actual,
+ expected_clipped,
+ rtol=0.01,
+ err_msg=f'Mismatch at period {p}, time {t}: expected {expected_clipped}, got {actual}',
+ )
+
+
+# ==================== Multi-Period Clustering Tests ====================
+
+
+def create_system_with_periods(timesteps: pd.DatetimeIndex, periods: pd.Index) -> fx.FlowSystem:
+ """Create a FlowSystem with periods for testing multi-period clustering."""
+ hours = len(timesteps)
+ # Create demand pattern that varies by day to ensure multiple clusters
+ hour_of_day = np.array([t.hour for t in timesteps])
+ day_of_year = np.arange(hours) // 24
+ # Add day-based variation: odd days have higher demand
+ base_demand = np.where((hour_of_day >= 8) & (hour_of_day < 18), 20, 8)
+ demand = base_demand * (1 + 0.3 * (day_of_year % 2)) # 30% higher on odd days
+
+ flow_system = fx.FlowSystem(timesteps, periods=periods)
+ flow_system.add_elements(
+ fx.Bus('Heat'),
+ fx.Bus('Gas'),
+ fx.Effect('costs', 'β¬', is_standard=True, is_objective=True),
+ fx.Sink('HeatDemand', inputs=[fx.Flow('Q', bus='Heat', fixed_relative_profile=demand, size=1)]),
+ fx.Source('GasSource', outputs=[fx.Flow('Gas', bus='Gas', effects_per_flow_hour=0.05)]),
+ fx.linear_converters.Boiler(
+ 'Boiler',
+ thermal_efficiency=0.9,
+ fuel_flow=fx.Flow('Q_fu', bus='Gas'),
+ thermal_flow=fx.Flow('Q_th', bus='Heat'),
+ ),
+ )
+ return flow_system
+
+
+def create_system_with_periods_and_scenarios(
+ timesteps: pd.DatetimeIndex, periods: pd.Index, scenarios: pd.Index
+) -> fx.FlowSystem:
+ """Create a FlowSystem with both periods and scenarios."""
+ import xarray as xr
+
+ hours = len(timesteps)
+
+ # Create demand that varies by scenario AND by day (for clustering)
+ hour_of_day = np.array([t.hour for t in timesteps])
+ day_of_year = np.arange(hours) // 24
+ base_demand = np.where((hour_of_day >= 8) & (hour_of_day < 18), 20, 8)
+ # Add day variation for clustering
+ base_demand = base_demand * (1 + 0.3 * (day_of_year % 2))
+
+ # Create demand array with explicit scenario dimension using xarray
+ # Shape: (time, scenario)
+ demand_data = np.column_stack([base_demand * (1 + 0.2 * i) for i in range(len(scenarios))])
+ demand_da = xr.DataArray(
+ demand_data,
+ dims=['time', 'scenario'],
+ coords={'time': timesteps, 'scenario': scenarios},
+ )
+
+ flow_system = fx.FlowSystem(timesteps, periods=periods, scenarios=scenarios)
+ flow_system.add_elements(
+ fx.Bus('Heat'),
+ fx.Bus('Gas'),
+ fx.Effect('costs', 'β¬', is_standard=True, is_objective=True),
+ fx.Sink(
+ 'HeatDemand',
+ inputs=[fx.Flow('Q', bus='Heat', fixed_relative_profile=demand_da, size=1)],
+ ),
+ fx.Source('GasSource', outputs=[fx.Flow('Gas', bus='Gas', effects_per_flow_hour=0.05)]),
+ fx.linear_converters.Boiler(
+ 'Boiler',
+ thermal_efficiency=0.9,
+ fuel_flow=fx.Flow('Q_fu', bus='Gas'),
+ thermal_flow=fx.Flow('Q_th', bus='Heat'),
+ ),
+ )
+ return flow_system
+
+
+@pytest.fixture
+def periods_2():
+ """Two periods for testing."""
+ return pd.Index([2020, 2021], name='period')
+
+
+class TestMultiPeriodClustering:
+ """Tests for clustering with periods dimension."""
+
+ def test_cluster_with_periods(self, timesteps_8_days, periods_2):
+ """Test clustering with periods dimension."""
+ fs = create_system_with_periods(timesteps_8_days, periods_2)
+
+ # Verify periods are set up correctly
+ assert fs.periods is not None
+ assert len(fs.periods) == 2
+
+ # Cluster
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ # Should have period dimension preserved
+ assert fs_clustered.periods is not None
+ assert len(fs_clustered.periods) == 2
+
+ # Clustered: 24 within-cluster timesteps, 2 clusters
+ assert len(fs_clustered.timesteps) == 24
+ assert len(fs_clustered.clusters) == 2
+
+ def test_cluster_with_periods_optimizes(self, solver_fixture, timesteps_8_days, periods_2):
+ """Test that clustering with periods can be optimized."""
+ fs = create_system_with_periods(timesteps_8_days, periods_2)
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Should have solution with period dimension
+ assert fs_clustered.solution is not None
+ flow_var = 'Boiler(Q_th)|flow_rate'
+ assert flow_var in fs_clustered.solution
+ assert 'period' in fs_clustered.solution[flow_var].dims
+
+ def test_expand_solution_with_periods(self, solver_fixture, timesteps_8_days, periods_2):
+ """Verify expansion handles period dimension correctly."""
+ fs = create_system_with_periods(timesteps_8_days, periods_2)
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Expand
+ fs_expanded = fs_clustered.transform.expand_solution()
+
+ # Should have original timesteps and periods
+ assert len(fs_expanded.timesteps) == 192
+ assert fs_expanded.periods is not None
+ assert len(fs_expanded.periods) == 2
+
+ # Solution should have period dimension
+ flow_var = 'Boiler(Q_th)|flow_rate'
+ assert 'period' in fs_expanded.solution[flow_var].dims
+ assert len(fs_expanded.solution[flow_var].coords['time']) == 193 # 192 + 1 extra timestep
+
+ def test_cluster_with_periods_and_scenarios(self, solver_fixture, timesteps_8_days, periods_2, scenarios_2):
+ """Clustering should work with both periods and scenarios."""
+ fs = create_system_with_periods_and_scenarios(timesteps_8_days, periods_2, scenarios_2)
+
+ # Verify setup
+ assert fs.periods is not None
+ assert fs.scenarios is not None
+ assert len(fs.periods) == 2
+ assert len(fs.scenarios) == 2
+
+ # Cluster and optimize
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs_clustered.optimize(solver_fixture)
+
+ # Verify dimensions
+ flow_var = 'Boiler(Q_th)|flow_rate'
+ assert 'period' in fs_clustered.solution[flow_var].dims
+ assert 'scenario' in fs_clustered.solution[flow_var].dims
+ assert 'cluster' in fs_clustered.solution[flow_var].dims
+
+ # Expand and verify
+ fs_expanded = fs_clustered.transform.expand_solution()
+ assert 'period' in fs_expanded.solution[flow_var].dims
+ assert 'scenario' in fs_expanded.solution[flow_var].dims
+ assert len(fs_expanded.solution[flow_var].coords['time']) == 193 # 192 + 1 extra timestep
+
+
+# ==================== Peak Selection Tests ====================
+
+
+def create_system_with_peak_demand(timesteps: pd.DatetimeIndex) -> fx.FlowSystem:
+ """Create a FlowSystem with clearly identifiable peak demand days."""
+ hours = len(timesteps)
+
+ # Create demand with distinct patterns to ensure multiple clusters
+ # Days 0,1: low demand (base pattern)
+ # Days 2,3: medium demand (higher pattern)
+ # Days 4,5,6: normal demand (moderate pattern)
+ # Day 7: extreme peak (very high)
+ day = np.arange(hours) // 24
+ hour_of_day = np.arange(hours) % 24
+
+ # Base pattern varies by day group
+ base = np.where((hour_of_day >= 8) & (hour_of_day < 18), 15, 5)
+
+ demand = np.where(
+ (day == 7) & (hour_of_day >= 10) & (hour_of_day < 14),
+ 50, # Extreme peak on day 7
+ np.where(
+ day <= 1,
+ base * 0.7, # Low days
+ np.where(day <= 3, base * 1.3, base), # Medium days vs normal
+ ),
+ )
+
+ flow_system = fx.FlowSystem(timesteps)
+ flow_system.add_elements(
+ fx.Bus('Heat'),
+ fx.Bus('Gas'),
+ fx.Effect('costs', 'β¬', is_standard=True, is_objective=True),
+ fx.Sink('HeatDemand', inputs=[fx.Flow('Q', bus='Heat', fixed_relative_profile=demand, size=1)]),
+ fx.Source('GasSource', outputs=[fx.Flow('Gas', bus='Gas', effects_per_flow_hour=0.05)]),
+ fx.linear_converters.Boiler(
+ 'Boiler',
+ thermal_efficiency=0.9,
+ fuel_flow=fx.Flow('Q_fu', bus='Gas'),
+ thermal_flow=fx.Flow('Q_th', bus='Heat'),
+ ),
+ )
+ return flow_system
+
+
+class TestPeakSelection:
+ """Tests for time_series_for_high_peaks and time_series_for_low_peaks parameters."""
+
+ def test_time_series_for_high_peaks_parameter_accepted(self, timesteps_8_days):
+ """Verify time_series_for_high_peaks parameter is accepted."""
+ fs = create_system_with_peak_demand(timesteps_8_days)
+
+ # Should not raise an error
+ fs_clustered = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ time_series_for_high_peaks=['HeatDemand(Q)|fixed_relative_profile'],
+ )
+
+ assert fs_clustered is not None
+ assert len(fs_clustered.clusters) == 2
+
+ def test_time_series_for_low_peaks_parameter_accepted(self, timesteps_8_days):
+ """Verify time_series_for_low_peaks parameter is accepted."""
+ fs = create_system_with_peak_demand(timesteps_8_days)
+
+ # Should not raise an error
+ # Note: tsam requires n_clusters >= 3 when using low_peaks to avoid index error
+ fs_clustered = fs.transform.cluster(
+ n_clusters=3,
+ cluster_duration='1D',
+ time_series_for_low_peaks=['HeatDemand(Q)|fixed_relative_profile'],
+ )
+
+ assert fs_clustered is not None
+ assert len(fs_clustered.clusters) == 3
+
+ def test_high_peaks_captures_extreme_demand_day(self, solver_fixture, timesteps_8_days):
+ """Verify high peak selection captures day with maximum demand."""
+ fs = create_system_with_peak_demand(timesteps_8_days)
+
+ # Cluster WITH high peak selection
+ fs_with_peaks = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ time_series_for_high_peaks=['HeatDemand(Q)|fixed_relative_profile'],
+ )
+ fs_with_peaks.optimize(solver_fixture)
+
+ # The peak day (day 7 with demand=50) should be captured
+ # Check that the clustered solution can handle the peak demand
+ flow_rates = fs_with_peaks.solution['Boiler(Q_th)|flow_rate']
+
+ # At least one cluster should have flow rate >= 50 (the peak)
+ max_flow = float(flow_rates.max())
+ assert max_flow >= 49, f'Peak demand not captured: max_flow={max_flow}'
+
+ def test_clustering_without_peaks_may_miss_extremes(self, solver_fixture, timesteps_8_days):
+ """Show that without peak selection, extreme days might be averaged out."""
+ fs = create_system_with_peak_demand(timesteps_8_days)
+
+ # Cluster WITHOUT high peak selection (may or may not capture peak)
+ fs_no_peaks = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ # No time_series_for_high_peaks
+ )
+ fs_no_peaks.optimize(solver_fixture)
+
+ # This test just verifies the clustering works
+ # The peak may or may not be captured depending on clustering algorithm
+ assert fs_no_peaks.solution is not None
diff --git a/tests/test_clustering/__init__.py b/tests/test_clustering/__init__.py
new file mode 100644
index 000000000..3d546645c
--- /dev/null
+++ b/tests/test_clustering/__init__.py
@@ -0,0 +1 @@
+"""Tests for the flixopt.clustering module."""
diff --git a/tests/test_clustering/test_base.py b/tests/test_clustering/test_base.py
new file mode 100644
index 000000000..9cca4de81
--- /dev/null
+++ b/tests/test_clustering/test_base.py
@@ -0,0 +1,158 @@
+"""Tests for flixopt.clustering.base module."""
+
+import numpy as np
+import pytest
+import xarray as xr
+
+from flixopt.clustering import (
+ Clustering,
+ ClusterResult,
+ ClusterStructure,
+ create_cluster_structure_from_mapping,
+)
+
+
+class TestClusterStructure:
+ """Tests for ClusterStructure dataclass."""
+
+ def test_basic_creation(self):
+ """Test basic ClusterStructure creation."""
+ cluster_order = xr.DataArray([0, 1, 0, 1, 2, 0], dims=['original_cluster'])
+ cluster_occurrences = xr.DataArray([3, 2, 1], dims=['cluster'])
+
+ structure = ClusterStructure(
+ cluster_order=cluster_order,
+ cluster_occurrences=cluster_occurrences,
+ n_clusters=3,
+ timesteps_per_cluster=24,
+ )
+
+ assert structure.n_clusters == 3
+ assert structure.timesteps_per_cluster == 24
+ assert structure.n_original_clusters == 6
+
+ def test_creation_from_numpy(self):
+ """Test ClusterStructure creation from numpy arrays."""
+ structure = ClusterStructure(
+ cluster_order=np.array([0, 0, 1, 1, 0]),
+ cluster_occurrences=np.array([3, 2]),
+ n_clusters=2,
+ timesteps_per_cluster=12,
+ )
+
+ assert isinstance(structure.cluster_order, xr.DataArray)
+ assert isinstance(structure.cluster_occurrences, xr.DataArray)
+ assert structure.n_original_clusters == 5
+
+ def test_get_cluster_weight_per_timestep(self):
+ """Test weight calculation per timestep."""
+ structure = ClusterStructure(
+ cluster_order=xr.DataArray([0, 1, 0], dims=['original_cluster']),
+ cluster_occurrences=xr.DataArray([2, 1], dims=['cluster']),
+ n_clusters=2,
+ timesteps_per_cluster=4,
+ )
+
+ weights = structure.get_cluster_weight_per_timestep()
+
+ # Cluster 0 has 4 timesteps, each with weight 2
+ # Cluster 1 has 4 timesteps, each with weight 1
+ assert len(weights) == 8
+ assert float(weights.isel(time=0).values) == 2.0
+ assert float(weights.isel(time=4).values) == 1.0
+
+
+class TestClusterResult:
+ """Tests for ClusterResult dataclass."""
+
+ def test_basic_creation(self):
+ """Test basic ClusterResult creation."""
+ result = ClusterResult(
+ timestep_mapping=xr.DataArray([0, 0, 1, 1, 2, 2], dims=['original_time']),
+ n_representatives=3,
+ representative_weights=xr.DataArray([2, 2, 2], dims=['time']),
+ )
+
+ assert result.n_representatives == 3
+ assert result.n_original_timesteps == 6
+
+ def test_creation_from_numpy(self):
+ """Test ClusterResult creation from numpy arrays."""
+ result = ClusterResult(
+ timestep_mapping=np.array([0, 1, 0, 1]),
+ n_representatives=2,
+ representative_weights=np.array([2.0, 2.0]),
+ )
+
+ assert isinstance(result.timestep_mapping, xr.DataArray)
+ assert isinstance(result.representative_weights, xr.DataArray)
+
+ def test_validation_success(self):
+ """Test validation passes for valid result."""
+ result = ClusterResult(
+ timestep_mapping=xr.DataArray([0, 1, 0, 1], dims=['original_time']),
+ n_representatives=2,
+ representative_weights=xr.DataArray([2.0, 2.0], dims=['time']),
+ )
+
+ # Should not raise
+ result.validate()
+
+ def test_validation_invalid_mapping(self):
+ """Test validation fails for out-of-range mapping."""
+ result = ClusterResult(
+ timestep_mapping=xr.DataArray([0, 5, 0, 1], dims=['original_time']), # 5 is out of range
+ n_representatives=2,
+ representative_weights=xr.DataArray([2.0, 2.0], dims=['time']),
+ )
+
+ with pytest.raises(ValueError, match='timestep_mapping contains index'):
+ result.validate()
+
+ def test_get_expansion_mapping(self):
+ """Test get_expansion_mapping returns named DataArray."""
+ result = ClusterResult(
+ timestep_mapping=xr.DataArray([0, 1, 0], dims=['original_time']),
+ n_representatives=2,
+ representative_weights=xr.DataArray([2.0, 1.0], dims=['time']),
+ )
+
+ mapping = result.get_expansion_mapping()
+ assert mapping.name == 'expansion_mapping'
+
+
+class TestCreateClusterStructureFromMapping:
+ """Tests for create_cluster_structure_from_mapping function."""
+
+ def test_basic_creation(self):
+ """Test creating ClusterStructure from timestep mapping."""
+ # 12 original timesteps, 4 per period, 3 periods
+ # Mapping: period 0 -> cluster 0, period 1 -> cluster 1, period 2 -> cluster 0
+ mapping = xr.DataArray(
+ [0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3], # First and third period map to cluster 0
+ dims=['original_time'],
+ )
+
+ structure = create_cluster_structure_from_mapping(mapping, timesteps_per_cluster=4)
+
+ assert structure.timesteps_per_cluster == 4
+ assert structure.n_original_clusters == 3
+
+
+class TestClustering:
+ """Tests for Clustering dataclass."""
+
+ def test_creation(self):
+ """Test Clustering creation."""
+ result = ClusterResult(
+ timestep_mapping=xr.DataArray([0, 1], dims=['original_time']),
+ n_representatives=2,
+ representative_weights=xr.DataArray([1.0, 1.0], dims=['time']),
+ )
+
+ info = Clustering(
+ result=result,
+ backend_name='tsam',
+ )
+
+ assert info.backend_name == 'tsam'
diff --git a/tests/test_clustering/test_integration.py b/tests/test_clustering/test_integration.py
new file mode 100644
index 000000000..16c638c95
--- /dev/null
+++ b/tests/test_clustering/test_integration.py
@@ -0,0 +1,286 @@
+"""Integration tests for flixopt.aggregation module with FlowSystem."""
+
+import numpy as np
+import pandas as pd
+import pytest
+import xarray as xr
+
+from flixopt import FlowSystem
+
+
+class TestWeights:
+ """Tests for FlowSystem.weights dict property."""
+
+ def test_weights_is_dict(self):
+ """Test weights returns a dict."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+ weights = fs.weights
+
+ assert isinstance(weights, dict)
+ assert 'time' in weights
+
+ def test_time_weight(self):
+ """Test weights['time'] returns timestep_duration."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+ weights = fs.weights
+
+ # For hourly data, timestep_duration is 1.0
+ assert float(weights['time'].mean()) == 1.0
+
+ def test_cluster_not_in_weights_when_non_clustered(self):
+ """Test weights doesn't have 'cluster' key for non-clustered systems."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+ weights = fs.weights
+
+ # Non-clustered: 'cluster' not in weights
+ assert 'cluster' not in weights
+
+ def test_temporal_dims_non_clustered(self):
+ """Test temporal_dims is ['time'] for non-clustered systems."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+
+ assert fs.temporal_dims == ['time']
+
+ def test_temporal_weight(self):
+ """Test temporal_weight returns time * cluster."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+
+ expected = fs.weights['time'] * fs.weights.get('cluster', 1.0)
+ xr.testing.assert_equal(fs.temporal_weight, expected)
+
+ def test_sum_temporal(self):
+ """Test sum_temporal applies full temporal weighting (time * cluster) and sums."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=3, freq='h'))
+
+ # Input is a rate (e.g., flow_rate in MW)
+ data = xr.DataArray([10.0, 20.0, 30.0], dims=['time'], coords={'time': fs.timesteps})
+
+ result = fs.sum_temporal(data)
+
+ # For hourly non-clustered: temporal = time * cluster = 1.0 * 1.0 = 1.0
+ # result = sum(data * temporal) = sum(data) = 60
+ assert float(result.values) == 60.0
+
+
+class TestFlowSystemDimsIndexesWeights:
+ """Tests for FlowSystem.dims, .indexes, .weights properties."""
+
+ def test_dims_property(self):
+ """Test that FlowSystem.dims returns active dimension names."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+
+ dims = fs.dims
+ assert dims == ['time']
+
+ def test_indexes_property(self):
+ """Test that FlowSystem.indexes returns active indexes."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+
+ indexes = fs.indexes
+ assert isinstance(indexes, dict)
+ assert 'time' in indexes
+ assert len(indexes['time']) == 24
+
+ def test_weights_keys_match_dims(self):
+ """Test that weights.keys() is subset of dims (only 'time' for simple case)."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+
+ # For non-clustered, weights only has 'time'
+ assert set(fs.weights.keys()) == {'time'}
+
+ def test_temporal_weight_calculation(self):
+ """Test that temporal_weight = timestep_duration * cluster_weight."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=24, freq='h'))
+
+ expected = fs.timestep_duration * 1.0 # cluster is 1.0 for non-clustered
+
+ np.testing.assert_array_almost_equal(fs.temporal_weight.values, expected.values)
+
+ def test_weights_with_cluster_weight(self):
+ """Test weights property includes cluster_weight when provided."""
+ # Create FlowSystem with custom cluster_weight
+ timesteps = pd.date_range('2024-01-01', periods=24, freq='h')
+ cluster_weight = xr.DataArray(
+ np.array([2.0] * 12 + [1.0] * 12),
+ dims=['time'],
+ coords={'time': timesteps},
+ )
+
+ fs = FlowSystem(timesteps=timesteps, cluster_weight=cluster_weight)
+
+ weights = fs.weights
+
+ # cluster weight should be in weights (FlowSystem has cluster_weight set)
+ # But note: 'cluster' only appears in weights if clusters dimension exists
+ # Since we didn't set clusters, 'cluster' won't be in weights
+ # The cluster_weight is applied via temporal_weight
+ assert 'cluster' not in weights # No cluster dimension
+
+ # temporal_weight = timestep_duration * cluster_weight
+ # timestep_duration is 1h for all
+ expected = 1.0 * cluster_weight
+ np.testing.assert_array_almost_equal(fs.temporal_weight.values, expected.values)
+
+
+class TestClusterMethod:
+ """Tests for FlowSystem.transform.cluster method."""
+
+ def test_cluster_method_exists(self):
+ """Test that transform.cluster method exists."""
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=48, freq='h'))
+
+ assert hasattr(fs.transform, 'cluster')
+ assert callable(fs.transform.cluster)
+
+ def test_cluster_reduces_timesteps(self):
+ """Test that cluster reduces timesteps."""
+ # This test requires tsam to be installed
+ pytest.importorskip('tsam')
+ from flixopt import Bus, Flow, Sink, Source
+ from flixopt.core import TimeSeriesData
+
+ # Create FlowSystem with 7 days of data (168 hours)
+ n_hours = 168 # 7 days
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=n_hours, freq='h'))
+
+ # Add some basic components with time series data
+ demand_data = np.sin(np.linspace(0, 14 * np.pi, n_hours)) + 2 # Varying demand over 7 days
+ bus = Bus('electricity')
+ # Bus label is passed as string to Flow
+ grid_flow = Flow('grid_in', bus='electricity', size=100)
+ demand_flow = Flow(
+ 'demand_out', bus='electricity', size=100, fixed_relative_profile=TimeSeriesData(demand_data / 100)
+ )
+ source = Source('grid', outputs=[grid_flow])
+ sink = Sink('demand', inputs=[demand_flow])
+ fs.add_elements(source, sink, bus)
+
+ # Reduce 7 days to 2 representative days
+ fs_clustered = fs.transform.cluster(
+ n_clusters=2,
+ cluster_duration='1D',
+ )
+
+ # Clustered FlowSystem has 2D structure: (cluster, time)
+ # - timesteps: within-cluster time (24 hours)
+ # - clusters: cluster indices (2 clusters)
+ # Total effective timesteps = 2 * 24 = 48
+ assert len(fs_clustered.timesteps) == 24 # Within-cluster time
+ assert len(fs_clustered.clusters) == 2 # Number of clusters
+ assert len(fs_clustered.timesteps) * len(fs_clustered.clusters) == 48
+
+
+class TestClusterAdvancedOptions:
+ """Tests for advanced clustering options."""
+
+ @pytest.fixture
+ def basic_flow_system(self):
+ """Create a basic FlowSystem for testing."""
+ pytest.importorskip('tsam')
+ from flixopt import Bus, Flow, Sink, Source
+ from flixopt.core import TimeSeriesData
+
+ n_hours = 168 # 7 days
+ fs = FlowSystem(timesteps=pd.date_range('2024-01-01', periods=n_hours, freq='h'))
+
+ demand_data = np.sin(np.linspace(0, 14 * np.pi, n_hours)) + 2
+ bus = Bus('electricity')
+ grid_flow = Flow('grid_in', bus='electricity', size=100)
+ demand_flow = Flow(
+ 'demand_out', bus='electricity', size=100, fixed_relative_profile=TimeSeriesData(demand_data / 100)
+ )
+ source = Source('grid', outputs=[grid_flow])
+ sink = Sink('demand', inputs=[demand_flow])
+ fs.add_elements(source, sink, bus)
+ return fs
+
+ def test_cluster_method_parameter(self, basic_flow_system):
+ """Test that cluster_method parameter works."""
+ fs_clustered = basic_flow_system.transform.cluster(
+ n_clusters=2, cluster_duration='1D', cluster_method='hierarchical'
+ )
+ assert len(fs_clustered.clusters) == 2
+
+ def test_hierarchical_is_deterministic(self, basic_flow_system):
+ """Test that hierarchical clustering (default) produces deterministic results."""
+ fs1 = basic_flow_system.transform.cluster(n_clusters=2, cluster_duration='1D')
+ fs2 = basic_flow_system.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ # Hierarchical clustering should produce identical cluster orders
+ xr.testing.assert_equal(fs1.clustering.cluster_order, fs2.clustering.cluster_order)
+
+ def test_metrics_available(self, basic_flow_system):
+ """Test that clustering metrics are available after clustering."""
+ fs_clustered = basic_flow_system.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ assert fs_clustered.clustering.metrics is not None
+ assert isinstance(fs_clustered.clustering.metrics, xr.Dataset)
+ assert 'time_series' in fs_clustered.clustering.metrics.dims
+ assert len(fs_clustered.clustering.metrics.data_vars) > 0
+
+ def test_representation_method_parameter(self, basic_flow_system):
+ """Test that representation_method parameter works."""
+ fs_clustered = basic_flow_system.transform.cluster(
+ n_clusters=2, cluster_duration='1D', representation_method='medoidRepresentation'
+ )
+ assert len(fs_clustered.clusters) == 2
+
+ def test_rescale_cluster_periods_parameter(self, basic_flow_system):
+ """Test that rescale_cluster_periods parameter works."""
+ fs_clustered = basic_flow_system.transform.cluster(
+ n_clusters=2, cluster_duration='1D', rescale_cluster_periods=False
+ )
+ assert len(fs_clustered.clusters) == 2
+
+ def test_tsam_kwargs_passthrough(self, basic_flow_system):
+ """Test that additional kwargs are passed to tsam."""
+ # sameMean is a valid tsam parameter
+ fs_clustered = basic_flow_system.transform.cluster(n_clusters=2, cluster_duration='1D', sameMean=True)
+ assert len(fs_clustered.clusters) == 2
+
+ def test_metrics_with_periods(self):
+ """Test that metrics have period dimension for multi-period FlowSystems."""
+ pytest.importorskip('tsam')
+ from flixopt import Bus, Flow, Sink, Source
+ from flixopt.core import TimeSeriesData
+
+ n_hours = 168 # 7 days
+ fs = FlowSystem(
+ timesteps=pd.date_range('2024-01-01', periods=n_hours, freq='h'),
+ periods=pd.Index([2025, 2030], name='period'),
+ )
+
+ demand_data = np.sin(np.linspace(0, 14 * np.pi, n_hours)) + 2
+ bus = Bus('electricity')
+ grid_flow = Flow('grid_in', bus='electricity', size=100)
+ demand_flow = Flow(
+ 'demand_out', bus='electricity', size=100, fixed_relative_profile=TimeSeriesData(demand_data / 100)
+ )
+ source = Source('grid', outputs=[grid_flow])
+ sink = Sink('demand', inputs=[demand_flow])
+ fs.add_elements(source, sink, bus)
+
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ # Metrics should have period dimension
+ assert fs_clustered.clustering.metrics is not None
+ assert 'period' in fs_clustered.clustering.metrics.dims
+ assert len(fs_clustered.clustering.metrics.period) == 2
+
+
+class TestClusteringModuleImports:
+ """Tests for flixopt.clustering module imports."""
+
+ def test_import_from_flixopt(self):
+ """Test that clustering module can be imported from flixopt."""
+ from flixopt import clustering
+
+ assert hasattr(clustering, 'ClusterResult')
+ assert hasattr(clustering, 'ClusterStructure')
+ assert hasattr(clustering, 'Clustering')
+
+ def test_create_cluster_structure_from_mapping_available(self):
+ """Test that create_cluster_structure_from_mapping is available."""
+ from flixopt.clustering import create_cluster_structure_from_mapping
+
+ assert callable(create_cluster_structure_from_mapping)
diff --git a/tests/test_clustering_io.py b/tests/test_clustering_io.py
new file mode 100644
index 000000000..483cdc447
--- /dev/null
+++ b/tests/test_clustering_io.py
@@ -0,0 +1,241 @@
+"""Tests for clustering serialization and deserialization."""
+
+import numpy as np
+import pandas as pd
+import pytest
+
+import flixopt as fx
+
+
+@pytest.fixture
+def simple_system_24h():
+ """Create a simple flow system with 24 hourly timesteps."""
+ timesteps = pd.date_range('2023-01-01', periods=24, freq='h')
+
+ fs = fx.FlowSystem(timesteps)
+ fs.add_elements(
+ fx.Bus('heat'),
+ fx.Effect('costs', unit='EUR', description='costs', is_objective=True, is_standard=True),
+ )
+ fs.add_elements(
+ fx.Sink('demand', inputs=[fx.Flow('in', bus='heat', fixed_relative_profile=np.ones(24), size=10)]),
+ fx.Source('source', outputs=[fx.Flow('out', bus='heat', size=50, effects_per_flow_hour={'costs': 0.05})]),
+ )
+ return fs
+
+
+@pytest.fixture
+def simple_system_8_days():
+ """Create a simple flow system with 8 days of hourly timesteps."""
+ timesteps = pd.date_range('2023-01-01', periods=8 * 24, freq='h')
+
+ # Create varying demand profile with different patterns for different days
+ # 4 "weekdays" with high demand, 4 "weekend" days with low demand
+ hourly_pattern = np.sin(np.linspace(0, 2 * np.pi, 24)) * 0.5 + 0.5
+ weekday_profile = hourly_pattern * 1.5 # Higher demand
+ weekend_profile = hourly_pattern * 0.5 # Lower demand
+ demand_profile = np.concatenate(
+ [
+ weekday_profile,
+ weekday_profile,
+ weekday_profile,
+ weekday_profile,
+ weekend_profile,
+ weekend_profile,
+ weekend_profile,
+ weekend_profile,
+ ]
+ )
+
+ fs = fx.FlowSystem(timesteps)
+ fs.add_elements(
+ fx.Bus('heat'),
+ fx.Effect('costs', unit='EUR', description='costs', is_objective=True, is_standard=True),
+ )
+ fs.add_elements(
+ fx.Sink('demand', inputs=[fx.Flow('in', bus='heat', fixed_relative_profile=demand_profile, size=10)]),
+ fx.Source('source', outputs=[fx.Flow('out', bus='heat', size=50, effects_per_flow_hour={'costs': 0.05})]),
+ )
+ return fs
+
+
+class TestClusteringRoundtrip:
+ """Test that clustering survives dataset roundtrip."""
+
+ def test_clustering_to_dataset_has_clustering_attrs(self, simple_system_8_days):
+ """Clustered FlowSystem dataset should have clustering info."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ ds = fs_clustered.to_dataset(include_solution=False)
+
+ # Check that clustering attrs are present
+ assert 'clustering' in ds.attrs
+
+ # Check that clustering arrays are present with prefix
+ clustering_vars = [name for name in ds.data_vars if name.startswith('clustering|')]
+ assert len(clustering_vars) > 0
+
+ def test_clustering_roundtrip_preserves_clustering_object(self, simple_system_8_days):
+ """Clustering object should be restored after roundtrip."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ # Roundtrip
+ ds = fs_clustered.to_dataset(include_solution=False)
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ # Clustering should be restored
+ assert fs_restored.clustering is not None
+ assert fs_restored.clustering.backend_name == 'tsam'
+
+ def test_clustering_roundtrip_preserves_n_clusters(self, simple_system_8_days):
+ """Number of clusters should be preserved after roundtrip."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ ds = fs_clustered.to_dataset(include_solution=False)
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ assert fs_restored.clustering.n_clusters == 2
+
+ def test_clustering_roundtrip_preserves_timesteps_per_cluster(self, simple_system_8_days):
+ """Timesteps per cluster should be preserved after roundtrip."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ ds = fs_clustered.to_dataset(include_solution=False)
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ assert fs_restored.clustering.timesteps_per_cluster == 24
+
+ def test_clustering_roundtrip_preserves_original_timesteps(self, simple_system_8_days):
+ """Original timesteps should be preserved after roundtrip."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ original_timesteps = fs_clustered.clustering.original_timesteps
+
+ ds = fs_clustered.to_dataset(include_solution=False)
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ pd.testing.assert_index_equal(fs_restored.clustering.original_timesteps, original_timesteps)
+
+ def test_clustering_roundtrip_preserves_timestep_mapping(self, simple_system_8_days):
+ """Timestep mapping should be preserved after roundtrip."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+ original_mapping = fs_clustered.clustering.timestep_mapping.values.copy()
+
+ ds = fs_clustered.to_dataset(include_solution=False)
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ np.testing.assert_array_equal(fs_restored.clustering.timestep_mapping.values, original_mapping)
+
+
+class TestClusteringWithSolutionRoundtrip:
+ """Test that clustering with solution survives roundtrip."""
+
+ def test_expand_solution_after_roundtrip(self, simple_system_8_days, solver_fixture):
+ """expand_solution should work after loading from dataset."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ # Solve
+ fs_clustered.optimize(solver_fixture)
+
+ # Roundtrip
+ ds = fs_clustered.to_dataset(include_solution=True)
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ # expand_solution should work
+ fs_expanded = fs_restored.transform.expand_solution()
+
+ # Check expanded FlowSystem has correct number of timesteps
+ assert len(fs_expanded.timesteps) == 8 * 24
+
+ def test_expand_solution_after_netcdf_roundtrip(self, simple_system_8_days, tmp_path, solver_fixture):
+ """expand_solution should work after loading from NetCDF file."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ # Solve
+ fs_clustered.optimize(solver_fixture)
+
+ # Save to NetCDF
+ nc_path = tmp_path / 'clustered.nc'
+ fs_clustered.to_netcdf(nc_path)
+
+ # Load from NetCDF
+ fs_restored = fx.FlowSystem.from_netcdf(nc_path)
+
+ # expand_solution should work
+ fs_expanded = fs_restored.transform.expand_solution()
+
+ # Check expanded FlowSystem has correct number of timesteps
+ assert len(fs_expanded.timesteps) == 8 * 24
+
+
+class TestClusteringDerivedProperties:
+ """Test derived properties on Clustering object."""
+
+ def test_original_timesteps_property(self, simple_system_8_days):
+ """original_timesteps property should return correct DatetimeIndex."""
+ fs = simple_system_8_days
+ original_timesteps = fs.timesteps
+
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ # Check values are equal (name attribute may differ)
+ pd.testing.assert_index_equal(
+ fs_clustered.clustering.original_timesteps,
+ original_timesteps,
+ check_names=False,
+ )
+
+ def test_simple_system_has_no_periods_or_scenarios(self, simple_system_8_days):
+ """Clustered simple system should preserve that it has no periods/scenarios."""
+ fs = simple_system_8_days
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ # FlowSystem without periods/scenarios should remain so after clustering
+ assert fs_clustered.periods is None
+ assert fs_clustered.scenarios is None
+
+
+class TestClusteringWithScenarios:
+ """Test clustering IO with scenarios."""
+
+ @pytest.fixture
+ def system_with_scenarios(self):
+ """Create a flow system with scenarios."""
+ timesteps = pd.date_range('2023-01-01', periods=4 * 24, freq='h')
+ scenarios = pd.Index(['Low', 'High'], name='scenario')
+
+ # Create varying demand profile for clustering
+ demand_profile = np.tile(np.sin(np.linspace(0, 2 * np.pi, 24)) * 0.5 + 0.5, 4)
+
+ fs = fx.FlowSystem(timesteps, scenarios=scenarios)
+ fs.add_elements(
+ fx.Bus('heat'),
+ fx.Effect('costs', unit='EUR', description='costs', is_objective=True, is_standard=True),
+ )
+ fs.add_elements(
+ fx.Sink('demand', inputs=[fx.Flow('in', bus='heat', fixed_relative_profile=demand_profile, size=10)]),
+ fx.Source('source', outputs=[fx.Flow('out', bus='heat', size=50, effects_per_flow_hour={'costs': 0.05})]),
+ )
+ return fs
+
+ def test_clustering_roundtrip_preserves_scenarios(self, system_with_scenarios):
+ """Scenarios should be preserved after clustering and roundtrip."""
+ fs = system_with_scenarios
+ fs_clustered = fs.transform.cluster(n_clusters=2, cluster_duration='1D')
+
+ ds = fs_clustered.to_dataset(include_solution=False)
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ # Scenarios should be preserved in the FlowSystem itself
+ pd.testing.assert_index_equal(
+ fs_restored.scenarios,
+ pd.Index(['Low', 'High'], name='scenario'),
+ check_names=False,
+ )
diff --git a/tests/test_effect.py b/tests/test_effect.py
index 015e054eb..60fbb0166 100644
--- a/tests/test_effect.py
+++ b/tests/test_effect.py
@@ -129,8 +129,8 @@ def test_bounds(self, basic_flow_system_linopy_coords, coords_config):
assert_var_equal(
model.variables['Effect1(temporal)|per_timestep'],
model.add_variables(
- lower=4.0 * model.hours_per_step,
- upper=4.1 * model.hours_per_step,
+ lower=4.0 * model.timestep_duration,
+ upper=4.1 * model.timestep_duration,
coords=model.get_coords(['time', 'period', 'scenario']),
),
)
diff --git a/tests/test_flow.py b/tests/test_flow.py
index 594bc1fbb..8e1ce1f53 100644
--- a/tests/test_flow.py
+++ b/tests/test_flow.py
@@ -23,7 +23,7 @@ def test_flow_minimal(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|total_flow_hours'],
flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.timestep_duration).sum('time'),
)
assert_var_equal(flow.submodel.flow_rate, model.add_variables(lower=0, upper=100, coords=model.get_coords()))
assert_var_equal(
@@ -61,7 +61,7 @@ def test_flow(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|total_flow_hours'],
flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.timestep_duration).sum('time'),
)
assert_var_equal(
@@ -83,12 +83,12 @@ def test_flow(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|load_factor_min'],
- flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours'] >= model.hours_per_step.sum('time') * 0.1 * 100,
+ flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours'] >= model.timestep_duration.sum('time') * 0.1 * 100,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|load_factor_max'],
- flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours'] <= model.hours_per_step.sum('time') * 0.9 * 100,
+ flow.submodel.variables['Sink(WΓ€rme)|total_flow_hours'] <= model.timestep_duration.sum('time') * 0.9 * 100,
)
assert_sets_equal(
@@ -129,13 +129,13 @@ def test_effects_per_flow_hour(self, basic_flow_system_linopy_coords, coords_con
assert_conequal(
model.constraints['Sink(WΓ€rme)->costs(temporal)'],
model.variables['Sink(WΓ€rme)->costs(temporal)']
- == flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.hours_per_step * costs_per_flow_hour,
+ == flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.timestep_duration * costs_per_flow_hour,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)->CO2(temporal)'],
model.variables['Sink(WΓ€rme)->CO2(temporal)']
- == flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.hours_per_step * co2_per_flow_hour,
+ == flow.submodel.variables['Sink(WΓ€rme)|flow_rate'] * model.timestep_duration * co2_per_flow_hour,
)
@@ -561,7 +561,7 @@ def test_flow_on(self, basic_flow_system_linopy_coords, coords_config):
model.add_variables(binary=True, coords=model.get_coords()),
)
# Upper bound is total hours when active_hours_max is not specified
- total_hours = model.hours_per_step.sum('time')
+ total_hours = model.timestep_duration.sum('time')
assert_var_equal(
model.variables['Sink(WΓ€rme)|active_hours'],
model.add_variables(lower=0, upper=total_hours, coords=model.get_coords(['period', 'scenario'])),
@@ -580,7 +580,7 @@ def test_flow_on(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|active_hours'],
flow.submodel.variables['Sink(WΓ€rme)|active_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration).sum('time'),
)
def test_effects_per_active_hour(self, basic_flow_system_linopy_coords, coords_config):
@@ -635,13 +635,13 @@ def test_effects_per_active_hour(self, basic_flow_system_linopy_coords, coords_c
assert_conequal(
model.constraints['Sink(WΓ€rme)->costs(temporal)'],
model.variables['Sink(WΓ€rme)->costs(temporal)']
- == flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step * costs_per_running_hour,
+ == flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration * costs_per_running_hour,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)->CO2(temporal)'],
model.variables['Sink(WΓ€rme)->CO2(temporal)']
- == flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step * co2_per_running_hour,
+ == flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration * co2_per_running_hour,
)
def test_consecutive_on_hours(self, basic_flow_system_linopy_coords, coords_config):
@@ -687,7 +687,7 @@ def test_consecutive_on_hours(self, basic_flow_system_linopy_coords, coords_conf
model.add_variables(lower=0, upper=8, coords=model.get_coords()),
)
- mega = model.hours_per_step.sum('time')
+ mega = model.timestep_duration.sum('time')
assert_conequal(
model.constraints['Sink(WΓ€rme)|uptime|ub'],
@@ -698,7 +698,7 @@ def test_consecutive_on_hours(self, basic_flow_system_linopy_coords, coords_conf
model.constraints['Sink(WΓ€rme)|uptime|forward'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(1, None))
<= model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1)),
+ + model.timestep_duration.isel(time=slice(None, -1)),
)
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
@@ -706,14 +706,14 @@ def test_consecutive_on_hours(self, basic_flow_system_linopy_coords, coords_conf
model.constraints['Sink(WΓ€rme)|uptime|backward'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(1, None))
>= model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1))
+ + model.timestep_duration.isel(time=slice(None, -1))
+ (model.variables['Sink(WΓ€rme)|status'].isel(time=slice(1, None)) - 1) * mega,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|uptime|initial'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=0)
- == model.variables['Sink(WΓ€rme)|status'].isel(time=0) * model.hours_per_step.isel(time=0),
+ == model.variables['Sink(WΓ€rme)|status'].isel(time=0) * model.timestep_duration.isel(time=0),
)
assert_conequal(
@@ -768,7 +768,7 @@ def test_consecutive_on_hours_previous(self, basic_flow_system_linopy_coords, co
model.add_variables(lower=0, upper=8, coords=model.get_coords()),
)
- mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 3
+ mega = model.timestep_duration.sum('time') + model.timestep_duration.isel(time=0) * 3
assert_conequal(
model.constraints['Sink(WΓ€rme)|uptime|ub'],
@@ -779,7 +779,7 @@ def test_consecutive_on_hours_previous(self, basic_flow_system_linopy_coords, co
model.constraints['Sink(WΓ€rme)|uptime|forward'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(1, None))
<= model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1)),
+ + model.timestep_duration.isel(time=slice(None, -1)),
)
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
@@ -787,14 +787,14 @@ def test_consecutive_on_hours_previous(self, basic_flow_system_linopy_coords, co
model.constraints['Sink(WΓ€rme)|uptime|backward'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(1, None))
>= model.variables['Sink(WΓ€rme)|uptime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1))
+ + model.timestep_duration.isel(time=slice(None, -1))
+ (model.variables['Sink(WΓ€rme)|status'].isel(time=slice(1, None)) - 1) * mega,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|uptime|initial'],
model.variables['Sink(WΓ€rme)|uptime'].isel(time=0)
- == model.variables['Sink(WΓ€rme)|status'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1 + 3)),
+ == model.variables['Sink(WΓ€rme)|status'].isel(time=0) * (model.timestep_duration.isel(time=0) * (1 + 3)),
)
assert_conequal(
@@ -850,7 +850,9 @@ def test_consecutive_off_hours(self, basic_flow_system_linopy_coords, coords_con
model.add_variables(lower=0, upper=12, coords=model.get_coords()),
)
- mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 1 # previously inactive for 1h
+ mega = (
+ model.timestep_duration.sum('time') + model.timestep_duration.isel(time=0) * 1
+ ) # previously inactive for 1h
assert_conequal(
model.constraints['Sink(WΓ€rme)|downtime|ub'],
@@ -861,7 +863,7 @@ def test_consecutive_off_hours(self, basic_flow_system_linopy_coords, coords_con
model.constraints['Sink(WΓ€rme)|downtime|forward'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(1, None))
<= model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1)),
+ + model.timestep_duration.isel(time=slice(None, -1)),
)
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
@@ -869,14 +871,14 @@ def test_consecutive_off_hours(self, basic_flow_system_linopy_coords, coords_con
model.constraints['Sink(WΓ€rme)|downtime|backward'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(1, None))
>= model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1))
+ + model.timestep_duration.isel(time=slice(None, -1))
+ (model.variables['Sink(WΓ€rme)|inactive'].isel(time=slice(1, None)) - 1) * mega,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|downtime|initial'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=0)
- == model.variables['Sink(WΓ€rme)|inactive'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1 + 1)),
+ == model.variables['Sink(WΓ€rme)|inactive'].isel(time=0) * (model.timestep_duration.isel(time=0) * (1 + 1)),
)
assert_conequal(
@@ -933,7 +935,7 @@ def test_consecutive_off_hours_previous(self, basic_flow_system_linopy_coords, c
model.add_variables(lower=0, upper=12, coords=model.get_coords()),
)
- mega = model.hours_per_step.sum('time') + model.hours_per_step.isel(time=0) * 2
+ mega = model.timestep_duration.sum('time') + model.timestep_duration.isel(time=0) * 2
assert_conequal(
model.constraints['Sink(WΓ€rme)|downtime|ub'],
@@ -944,7 +946,7 @@ def test_consecutive_off_hours_previous(self, basic_flow_system_linopy_coords, c
model.constraints['Sink(WΓ€rme)|downtime|forward'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(1, None))
<= model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1)),
+ + model.timestep_duration.isel(time=slice(None, -1)),
)
# eq: duration(t) >= duration(t - 1) + dt(t) + (On(t) - 1) * BIG
@@ -952,14 +954,14 @@ def test_consecutive_off_hours_previous(self, basic_flow_system_linopy_coords, c
model.constraints['Sink(WΓ€rme)|downtime|backward'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(1, None))
>= model.variables['Sink(WΓ€rme)|downtime'].isel(time=slice(None, -1))
- + model.hours_per_step.isel(time=slice(None, -1))
+ + model.timestep_duration.isel(time=slice(None, -1))
+ (model.variables['Sink(WΓ€rme)|inactive'].isel(time=slice(1, None)) - 1) * mega,
)
assert_conequal(
model.constraints['Sink(WΓ€rme)|downtime|initial'],
model.variables['Sink(WΓ€rme)|downtime'].isel(time=0)
- == model.variables['Sink(WΓ€rme)|inactive'].isel(time=0) * (model.hours_per_step.isel(time=0) * (1 + 2)),
+ == model.variables['Sink(WΓ€rme)|inactive'].isel(time=0) * (model.timestep_duration.isel(time=0) * (1 + 2)),
)
assert_conequal(
@@ -1067,7 +1069,7 @@ def test_on_hours_limits(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['Sink(WΓ€rme)|active_hours'],
flow.submodel.variables['Sink(WΓ€rme)|active_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration).sum('time'),
)
@@ -1131,7 +1133,7 @@ def test_flow_on_invest_optional(self, basic_flow_system_linopy_coords, coords_c
model.add_variables(binary=True, coords=model.get_coords()),
)
# Upper bound is total hours when active_hours_max is not specified
- total_hours = model.hours_per_step.sum('time')
+ total_hours = model.timestep_duration.sum('time')
assert_var_equal(
model.variables['Sink(WΓ€rme)|active_hours'],
model.add_variables(lower=0, upper=total_hours, coords=model.get_coords(['period', 'scenario'])),
@@ -1157,7 +1159,7 @@ def test_flow_on_invest_optional(self, basic_flow_system_linopy_coords, coords_c
assert_conequal(
model.constraints['Sink(WΓ€rme)|active_hours'],
flow.submodel.variables['Sink(WΓ€rme)|active_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration).sum('time'),
)
# Investment
@@ -1233,7 +1235,7 @@ def test_flow_on_invest_non_optional(self, basic_flow_system_linopy_coords, coor
model.add_variables(binary=True, coords=model.get_coords()),
)
# Upper bound is total hours when active_hours_max is not specified
- total_hours = model.hours_per_step.sum('time')
+ total_hours = model.timestep_duration.sum('time')
assert_var_equal(
model.variables['Sink(WΓ€rme)|active_hours'],
model.add_variables(lower=0, upper=total_hours, coords=model.get_coords(['period', 'scenario'])),
@@ -1251,7 +1253,7 @@ def test_flow_on_invest_non_optional(self, basic_flow_system_linopy_coords, coor
assert_conequal(
model.constraints['Sink(WΓ€rme)|active_hours'],
flow.submodel.variables['Sink(WΓ€rme)|active_hours']
- == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.hours_per_step).sum('time'),
+ == (flow.submodel.variables['Sink(WΓ€rme)|status'] * model.timestep_duration).sum('time'),
)
# Investment
diff --git a/tests/test_flow_system_resample.py b/tests/test_flow_system_resample.py
index 7486b173c..dd5e19176 100644
--- a/tests/test_flow_system_resample.py
+++ b/tests/test_flow_system_resample.py
@@ -128,7 +128,7 @@ def test_time_metadata_updated(simple_fs):
"""Test time metadata correctly updated."""
fs_r = simple_fs.resample('3h', method='mean')
assert len(fs_r.timesteps) == 8
- assert_allclose(fs_r.hours_per_timestep.values, 3.0)
+ assert_allclose(fs_r.timestep_duration.values, 3.0)
assert fs_r.hours_of_last_timestep == 3.0
diff --git a/tests/test_io_conversion.py b/tests/test_io_conversion.py
index 33bda8c91..7775f987a 100644
--- a/tests/test_io_conversion.py
+++ b/tests/test_io_conversion.py
@@ -762,6 +762,11 @@ def test_v4_reoptimized_objective_matches_original(self, result_name):
new_objective = float(fs.solution['objective'].item())
new_effect_total = float(fs.solution[objective_effect_label].sum().item())
+ # Skip comparison for scenarios test case - scenario weights are now always normalized,
+ # which changes the objective value when loading old results with non-normalized weights
+ if result_name == '04_scenarios':
+ pytest.skip('Scenario weights are now always normalized - old results have different weights')
+
# Verify objective matches (within tolerance)
assert new_objective == pytest.approx(old_objective, rel=1e-5, abs=1), (
f'Objective mismatch for {result_name}: new={new_objective}, old={old_objective}'
diff --git a/tests/test_linear_converter.py b/tests/test_linear_converter.py
index 57b911d64..d20d104d0 100644
--- a/tests/test_linear_converter.py
+++ b/tests/test_linear_converter.py
@@ -174,7 +174,7 @@ def test_linear_converter_with_status(self, basic_flow_system_linopy_coords, coo
assert_conequal(
model.constraints['Converter|active_hours'],
model.variables['Converter|active_hours']
- == (model.variables['Converter|status'] * model.hours_per_step).sum('time'),
+ == (model.variables['Converter|status'] * model.timestep_duration).sum('time'),
)
# Check conversion constraint
@@ -188,7 +188,7 @@ def test_linear_converter_with_status(self, basic_flow_system_linopy_coords, coo
assert_conequal(
model.constraints['Converter->costs(temporal)'],
model.variables['Converter->costs(temporal)']
- == model.variables['Converter|status'] * model.hours_per_step * 5,
+ == model.variables['Converter|status'] * model.timestep_duration * 5,
)
def test_linear_converter_multidimensional(self, basic_flow_system_linopy_coords, coords_config):
@@ -485,7 +485,7 @@ def test_piecewise_conversion_with_status(self, basic_flow_system_linopy_coords,
assert 'Converter|active_hours' in model.constraints
assert_conequal(
model.constraints['Converter|active_hours'],
- model['Converter|active_hours'] == (model['Converter|status'] * model.hours_per_step).sum('time'),
+ model['Converter|active_hours'] == (model['Converter|status'] * model.timestep_duration).sum('time'),
)
# Verify that the costs effect is applied
@@ -493,7 +493,7 @@ def test_piecewise_conversion_with_status(self, basic_flow_system_linopy_coords,
assert_conequal(
model.constraints['Converter->costs(temporal)'],
model.variables['Converter->costs(temporal)']
- == model.variables['Converter|status'] * model.hours_per_step * 5,
+ == model.variables['Converter|status'] * model.timestep_duration * 5,
)
diff --git a/tests/test_on_hours_computation.py b/tests/test_on_hours_computation.py
index 578fd7792..c74332565 100644
--- a/tests/test_on_hours_computation.py
+++ b/tests/test_on_hours_computation.py
@@ -9,7 +9,7 @@ class TestComputeConsecutiveDuration:
"""Tests for the compute_consecutive_hours_in_state static method."""
@pytest.mark.parametrize(
- 'binary_values, hours_per_timestep, expected',
+ 'binary_values, timestep_duration, expected',
[
# Case 1: Single timestep DataArrays
(xr.DataArray([1], dims=['time']), 5, 5),
@@ -26,22 +26,22 @@ class TestComputeConsecutiveDuration:
(xr.DataArray([0, 1, 1, 1, 0, 0], dims=['time']), 1, 0), # ends with 0
],
)
- def test_compute_duration(self, binary_values, hours_per_timestep, expected):
+ def test_compute_duration(self, binary_values, timestep_duration, expected):
"""Test compute_consecutive_hours_in_state with various inputs."""
- result = ModelingUtilities.compute_consecutive_hours_in_state(binary_values, hours_per_timestep)
+ result = ModelingUtilities.compute_consecutive_hours_in_state(binary_values, timestep_duration)
assert np.isclose(result, expected)
@pytest.mark.parametrize(
- 'binary_values, hours_per_timestep',
+ 'binary_values, timestep_duration',
[
- # Case: hours_per_timestep must be scalar
+ # Case: timestep_duration must be scalar
(xr.DataArray([1, 1, 1, 1, 1], dims=['time']), np.array([1, 2])),
],
)
- def test_compute_duration_raises_error(self, binary_values, hours_per_timestep):
+ def test_compute_duration_raises_error(self, binary_values, timestep_duration):
"""Test error conditions."""
with pytest.raises(TypeError):
- ModelingUtilities.compute_consecutive_hours_in_state(binary_values, hours_per_timestep)
+ ModelingUtilities.compute_consecutive_hours_in_state(binary_values, timestep_duration)
class TestComputePreviousOnStates:
diff --git a/tests/test_scenarios.py b/tests/test_scenarios.py
index 65ea62d81..2699647ad 100644
--- a/tests/test_scenarios.py
+++ b/tests/test_scenarios.py
@@ -341,12 +341,14 @@ def test_scenarios_selection(flow_system_piecewise_conversion_scenarios):
assert flow_system.scenarios.equals(flow_system_full.scenarios[0:2])
- np.testing.assert_allclose(flow_system.scenario_weights.values, flow_system_full.scenario_weights[0:2])
+ # Scenario weights are always normalized - subset is re-normalized to sum to 1
+ subset_weights = flow_system_full.scenario_weights[0:2]
+ expected_normalized = subset_weights / subset_weights.sum()
+ np.testing.assert_allclose(flow_system.scenario_weights.values, expected_normalized.values)
- # Optimize using new API with normalize_weights=False
+ # Optimize using new API
flow_system.optimize(
fx.solvers.GurobiSolver(mip_gap=0.01, time_limit_seconds=60),
- normalize_weights=False,
)
# Penalty has same structure as other effects: 'Penalty' is the total, 'Penalty(temporal)' and 'Penalty(periodic)' are components
@@ -769,7 +771,10 @@ def test_weights_selection():
# Verify weights are correctly sliced
assert fs_subset.scenarios.equals(pd.Index(['base', 'high'], name='scenario'))
- np.testing.assert_allclose(fs_subset.scenario_weights.values, custom_scenario_weights[[0, 2]])
+ # Scenario weights are always normalized - subset is re-normalized to sum to 1
+ subset_weights = np.array([0.3, 0.2]) # Original weights for selected scenarios
+ expected_normalized = subset_weights / subset_weights.sum()
+ np.testing.assert_allclose(fs_subset.scenario_weights.values, expected_normalized)
# Verify weights are 1D with just scenario dimension (no period dimension)
assert fs_subset.scenario_weights.dims == ('scenario',)
diff --git a/tests/test_sel_isel_single_selection.py b/tests/test_sel_isel_single_selection.py
new file mode 100644
index 000000000..4d84ced51
--- /dev/null
+++ b/tests/test_sel_isel_single_selection.py
@@ -0,0 +1,193 @@
+"""Tests for sel/isel with single period/scenario selection."""
+
+import numpy as np
+import pandas as pd
+import pytest
+
+import flixopt as fx
+
+
+@pytest.fixture
+def fs_with_scenarios():
+ """FlowSystem with scenarios for testing single selection."""
+ timesteps = pd.date_range('2023-01-01', periods=24, freq='h')
+ scenarios = pd.Index(['A', 'B', 'C'], name='scenario')
+ scenario_weights = np.array([0.5, 0.3, 0.2])
+
+ fs = fx.FlowSystem(timesteps, scenarios=scenarios, scenario_weights=scenario_weights)
+ fs.add_elements(
+ fx.Bus('heat'),
+ fx.Effect('costs', unit='EUR', description='costs', is_objective=True, is_standard=True),
+ )
+ fs.add_elements(
+ fx.Sink('demand', inputs=[fx.Flow('in', bus='heat', fixed_relative_profile=np.ones(24), size=10)]),
+ fx.Source('source', outputs=[fx.Flow('out', bus='heat', size=50, effects_per_flow_hour={'costs': 0.05})]),
+ )
+ return fs
+
+
+@pytest.fixture
+def fs_with_periods():
+ """FlowSystem with periods for testing single selection."""
+ timesteps = pd.date_range('2023-01-01', periods=24, freq='h')
+ periods = pd.Index([2020, 2030, 2040], name='period')
+
+ fs = fx.FlowSystem(timesteps, periods=periods, weight_of_last_period=10)
+ fs.add_elements(
+ fx.Bus('heat'),
+ fx.Effect('costs', unit='EUR', description='costs', is_objective=True, is_standard=True),
+ )
+ fs.add_elements(
+ fx.Sink('demand', inputs=[fx.Flow('in', bus='heat', fixed_relative_profile=np.ones(24), size=10)]),
+ fx.Source('source', outputs=[fx.Flow('out', bus='heat', size=50, effects_per_flow_hour={'costs': 0.05})]),
+ )
+ return fs
+
+
+@pytest.fixture
+def fs_with_periods_and_scenarios():
+ """FlowSystem with both periods and scenarios."""
+ timesteps = pd.date_range('2023-01-01', periods=24, freq='h')
+ periods = pd.Index([2020, 2030], name='period')
+ scenarios = pd.Index(['Low', 'High'], name='scenario')
+
+ fs = fx.FlowSystem(timesteps, periods=periods, scenarios=scenarios, weight_of_last_period=10)
+ fs.add_elements(
+ fx.Bus('heat'),
+ fx.Effect('costs', unit='EUR', description='costs', is_objective=True, is_standard=True),
+ )
+ fs.add_elements(
+ fx.Sink('demand', inputs=[fx.Flow('in', bus='heat', fixed_relative_profile=np.ones(24), size=10)]),
+ fx.Source('source', outputs=[fx.Flow('out', bus='heat', size=50, effects_per_flow_hour={'costs': 0.05})]),
+ )
+ return fs
+
+
+class TestIselSingleScenario:
+ """Test isel with single scenario selection."""
+
+ def test_isel_single_scenario_drops_dimension(self, fs_with_scenarios):
+ """Selecting a single scenario with isel should drop the scenario dimension."""
+ fs_selected = fs_with_scenarios.transform.isel(scenario=0)
+
+ assert fs_selected.scenarios is None
+ assert 'scenario' not in fs_selected.to_dataset().dims
+
+ def test_isel_single_scenario_removes_scenario_weights(self, fs_with_scenarios):
+ """scenario_weights should be removed when scenario dimension is dropped."""
+ fs_selected = fs_with_scenarios.transform.isel(scenario=0)
+
+ ds = fs_selected.to_dataset()
+ assert 'scenario_weights' not in ds.data_vars
+ assert 'scenario_weights' not in ds.attrs
+
+ def test_isel_single_scenario_preserves_time(self, fs_with_scenarios):
+ """Time dimension should be preserved."""
+ fs_selected = fs_with_scenarios.transform.isel(scenario=0)
+
+ assert len(fs_selected.timesteps) == 24
+
+ def test_isel_single_scenario_roundtrip(self, fs_with_scenarios):
+ """FlowSystem should survive to_dataset/from_dataset roundtrip after single selection."""
+ fs_selected = fs_with_scenarios.transform.isel(scenario=0)
+
+ ds = fs_selected.to_dataset()
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ assert fs_restored.scenarios is None
+ assert len(fs_restored.timesteps) == 24
+
+
+class TestSelSingleScenario:
+ """Test sel with single scenario selection."""
+
+ def test_sel_single_scenario_drops_dimension(self, fs_with_scenarios):
+ """Selecting a single scenario with sel should drop the scenario dimension."""
+ fs_selected = fs_with_scenarios.transform.sel(scenario='B')
+
+ assert fs_selected.scenarios is None
+
+
+class TestIselSinglePeriod:
+ """Test isel with single period selection."""
+
+ def test_isel_single_period_drops_dimension(self, fs_with_periods):
+ """Selecting a single period with isel should drop the period dimension."""
+ fs_selected = fs_with_periods.transform.isel(period=0)
+
+ assert fs_selected.periods is None
+ assert 'period' not in fs_selected.to_dataset().dims
+
+ def test_isel_single_period_removes_period_weights(self, fs_with_periods):
+ """period_weights should be removed when period dimension is dropped."""
+ fs_selected = fs_with_periods.transform.isel(period=0)
+
+ ds = fs_selected.to_dataset()
+ assert 'period_weights' not in ds.data_vars
+ assert 'weight_of_last_period' not in ds.attrs
+
+ def test_isel_single_period_roundtrip(self, fs_with_periods):
+ """FlowSystem should survive roundtrip after single period selection."""
+ fs_selected = fs_with_periods.transform.isel(period=0)
+
+ ds = fs_selected.to_dataset()
+ fs_restored = fx.FlowSystem.from_dataset(ds)
+
+ assert fs_restored.periods is None
+
+
+class TestSelSinglePeriod:
+ """Test sel with single period selection."""
+
+ def test_sel_single_period_drops_dimension(self, fs_with_periods):
+ """Selecting a single period with sel should drop the period dimension."""
+ fs_selected = fs_with_periods.transform.sel(period=2030)
+
+ assert fs_selected.periods is None
+
+
+class TestMixedSelection:
+ """Test mixed selections (single + multiple)."""
+
+ def test_single_period_multiple_scenarios(self, fs_with_periods_and_scenarios):
+ """Single period but multiple scenarios should only drop period."""
+ fs_selected = fs_with_periods_and_scenarios.transform.isel(period=0)
+
+ assert fs_selected.periods is None
+ assert fs_selected.scenarios is not None
+ assert len(fs_selected.scenarios) == 2
+
+ def test_multiple_periods_single_scenario(self, fs_with_periods_and_scenarios):
+ """Multiple periods but single scenario should only drop scenario."""
+ fs_selected = fs_with_periods_and_scenarios.transform.isel(scenario=0)
+
+ assert fs_selected.periods is not None
+ assert len(fs_selected.periods) == 2
+ assert fs_selected.scenarios is None
+
+ def test_single_period_single_scenario(self, fs_with_periods_and_scenarios):
+ """Single period and single scenario should drop both."""
+ fs_selected = fs_with_periods_and_scenarios.transform.isel(period=0, scenario=0)
+
+ assert fs_selected.periods is None
+ assert fs_selected.scenarios is None
+
+
+class TestSliceSelection:
+ """Test that slice selection preserves dimensions."""
+
+ def test_slice_scenarios_preserves_dimension(self, fs_with_scenarios):
+ """Slice selection should preserve dimension even with 1 element."""
+ # Select a slice that results in 2 elements
+ fs_selected = fs_with_scenarios.transform.isel(scenario=slice(0, 2))
+
+ assert fs_selected.scenarios is not None
+ assert len(fs_selected.scenarios) == 2
+
+ def test_list_selection_preserves_dimension(self, fs_with_scenarios):
+ """List selection should preserve dimension even with 1 element."""
+ fs_selected = fs_with_scenarios.transform.isel(scenario=[0])
+
+ # List selection should preserve dimension
+ assert fs_selected.scenarios is not None
+ assert len(fs_selected.scenarios) == 1
diff --git a/tests/test_storage.py b/tests/test_storage.py
index 15170a321..3fd47fbf8 100644
--- a/tests/test_storage.py
+++ b/tests/test_storage.py
@@ -73,8 +73,8 @@ def test_basic_storage(self, basic_flow_system_linopy_coords, coords_config):
model.constraints['TestStorage|charge_state'],
charge_state.isel(time=slice(1, None))
== charge_state.isel(time=slice(None, -1))
- + model.variables['TestStorage(Q_th_in)|flow_rate'] * model.hours_per_step
- - model.variables['TestStorage(Q_th_out)|flow_rate'] * model.hours_per_step,
+ + model.variables['TestStorage(Q_th_in)|flow_rate'] * model.timestep_duration
+ - model.variables['TestStorage(Q_th_out)|flow_rate'] * model.timestep_duration,
)
# Check initial charge state constraint
assert_conequal(
@@ -146,7 +146,7 @@ def test_lossy_storage(self, basic_flow_system_linopy_coords, coords_config):
charge_state = model.variables['TestStorage|charge_state']
rel_loss = 0.05
- hours_per_step = model.hours_per_step
+ timestep_duration = model.timestep_duration
charge_rate = model.variables['TestStorage(Q_th_in)|flow_rate']
discharge_rate = model.variables['TestStorage(Q_th_out)|flow_rate']
eff_charge = 0.9
@@ -155,9 +155,9 @@ def test_lossy_storage(self, basic_flow_system_linopy_coords, coords_config):
assert_conequal(
model.constraints['TestStorage|charge_state'],
charge_state.isel(time=slice(1, None))
- == charge_state.isel(time=slice(None, -1)) * (1 - rel_loss) ** hours_per_step
- + charge_rate * eff_charge * hours_per_step
- - discharge_rate / eff_discharge * hours_per_step,
+ == charge_state.isel(time=slice(None, -1)) * (1 - rel_loss) ** timestep_duration
+ + charge_rate * eff_charge * timestep_duration
+ - discharge_rate / eff_discharge * timestep_duration,
)
# Check initial charge state constraint
@@ -242,8 +242,8 @@ def test_charge_state_bounds(self, basic_flow_system_linopy_coords, coords_confi
model.constraints['TestStorage|charge_state'],
charge_state.isel(time=slice(1, None))
== charge_state.isel(time=slice(None, -1))
- + model.variables['TestStorage(Q_th_in)|flow_rate'] * model.hours_per_step
- - model.variables['TestStorage(Q_th_out)|flow_rate'] * model.hours_per_step,
+ + model.variables['TestStorage(Q_th_in)|flow_rate'] * model.timestep_duration
+ - model.variables['TestStorage(Q_th_out)|flow_rate'] * model.timestep_duration,
)
# Check initial charge state constraint
assert_conequal(