Skip to content

Parsing profile with 15 minute timestepping - #513

Open
tolga-akan wants to merge 10 commits into
mainfrom
491-15-minute-timestepping
Open

Parsing profile with 15 minute timestepping#513
tolga-akan wants to merge 10 commits into
mainfrom
491-15-minute-timestepping

Conversation

@tolga-akan

@tolga-akan tolga-akan commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Currently timestepping is by default 1 hour.
The goal is to support also 15min timesteps in the data, but only if the data is also required with 15minute timesteps.

  • Updated/check profile parsing such that it parses 15min data as 15minute.
  • Updated/check profile averaging for x hours/days are taking accordingly when bigger timesteps are requested.
  • Add test that checks the profile parsing for 15min timesteps and that the right amount of variable with correct timesteps are created
  • Create a test where the optimization is tested with 15min timesteps and check that there are no other strange things happening with indexing. This test should not happen with the grow workflow, but should be on a test problem and should also include a producer and electricity profile.

@tolga-akan tolga-akan linked an issue Jul 15, 2026 that may be closed by this pull request
4 tasks
@tolga-akan
tolga-akan marked this pull request as ready for review July 15, 2026 15:22
@tolga-akan

Copy link
Copy Markdown
Collaborator Author

@FJanssen-TNO @KobusVanRooyen Ready for reviewing

Comment thread src/mesido/workflows/utils/adapt_profiles.py
f"Supported: 3600 s (1 h) or 900 s (15 min)."
)

steps_per_hour = 3600 // timestep_spacing_seconds # 1 for 1-h input, 4 for 15-min input

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to "org_steps_per_hour" then it is clear that this was the number of steps per hour for the original timeserie.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggested renaming is done

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name has not been updated as far as I can see.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right. I am surprised. I remember that I renamed. Probably I have reverted by mistake. Now i have renamed.

Comment thread tests/models/source_pipe_sink/input/timeseries_import_15min.csv
Comment thread tests/test_profile_parsing.py Outdated
Comment thread tests/test_profile_parsing.py Outdated
Comment thread tests/test_profile_parsing.py Outdated
Comment thread CHANGELOG.md Outdated

@tolga-akan tolga-akan left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@FJanssen-TNO PR is not ready yet. I will continue after vacation.

Comment thread src/mesido/workflows/utils/adapt_profiles.py
f"Supported: 3600 s (1 h) or 900 s (15 min)."
)

steps_per_hour = 3600 // timestep_spacing_seconds # 1 for 1-h input, 4 for 15-min input

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggested renaming is done

Comment thread CHANGELOG.md Outdated
Comment thread tests/test_profile_parsing.py Outdated
Comment thread tests/test_profile_parsing.py Outdated
@FJanssen-TNO

Copy link
Copy Markdown
Collaborator

@tolga-akan There is good reason why this is happening. Timestep 0 is considered the history in MESIDO, so when you are creating a profile and you are taking the average over a longer period, you need to start your timeseries first with a another value, in the method you used, the first timestep is therefore copied. After all the averages should be correct.

@tolga-akan

Copy link
Copy Markdown
Collaborator Author

@tolga-akan There is good reason why this is happening. Timestep 0 is considered the history in MESIDO, so when you are creating a profile and you are taking the average over a longer period, you need to start your timeseries first with a another value, in the method you used, the first timestep is therefore copied. After all the averages should be correct.

yes you are right. there is no issue wit that check now

@tolga-akan

Copy link
Copy Markdown
Collaborator Author

@FJanssen-TNO Ready to review

f"Supported: 3600 s (1 h) or 900 s (15 min)."
)

steps_per_hour = 3600 // timestep_spacing_seconds # 1 for 1-h input, 4 for 15-min input

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name has not been updated as far as I can see.

Comment thread tests/test_profile_parsing.py Outdated
Comment on lines +79 to +80
input_n_days = 0.25 # length of input profile in days
input_n_steps = input_n_days * 24 * (3600 / input_timestep_seconds)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please just use 8hrs*3600/input_timestep_seconds

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually i liked the way I have done before, because it was parametrizing the variable with input_n_days. input_n_days is also used at the later moment in the code. anyways, i updated the line as you recommend.

Comment thread tests/test_profile_parsing.py Outdated
len(datetimes),
expected_n_output_intervals + 1, # +1 for closing sentinel
)
dts = [datetimes[i + 1] - datetimes[i] for i in range(len(datetimes) - 1)]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is a nested forloop used for this? can it not be done with a vector operation?
You could use np.diff()
Also instead of datetimes you could just extract problem.times(), that will provide you with timestamps in seconds. Then the actual_step_seconds no longer needs to calcualted separately.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it can be done only via np.diff(problem.times()). redundant check is removed

Comment thread tests/test_profile_parsing.py Outdated
Comment on lines +109 to +116
np.testing.assert_array_equal(
expected_step_seconds,
actual_step_seconds,
)
np.testing.assert_array_equal(
expected_step_seconds,
np.diff(problem.times()),
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the difference between these two checks.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant check is removed

Comment thread tests/test_profile_parsing.py Outdated
Comment on lines +120 to +124
parsed_input_data = pd.read_csv(
input_csv_path,
parse_dates=["DateTime"],
dayfirst=True,
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do this before the for loop over the different day_steps as it is the same both times.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you are right. Since I added the for loop later, I forgot to check if I call the variables unnecessarily many times. now the things can be called outside of the loop are moved out.

Comment thread tests/test_profile_parsing.py Outdated
Comment on lines +140 to +144
np.testing.assert_array_equal(
len(averaged_profile),
expected_n_output_intervals,
err_msg=f"Unexpected averaged profile length for '{var_name}'",
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is unnecessary, the next test will fail if the length of the arrays is different

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes. Thats correct. check is removed

Comment thread tests/test_profile_parsing.py Outdated
Comment on lines +137 to +138
if len(averaged_profile) == expected_n_output_intervals + 1:
averaged_profile = averaged_profile[1:]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this not required every time this test is done? Because then remove the if statement.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This if condition is unnecessary. I forgot to remove this. Previously I added this for a debugging purpose. Now if is removed

Comment thread CHANGELOG.md Outdated

## Added
- ESDL profile reading and writing for different types: influxdb and postgres, and inline (in ESDL file).
- Parsing of input profiles with 15-minute interval

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to "changed": Parsing of input profiles with 15-minute interval now supported.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changelog is updated


def parameters(self, ensemble_member):
parameters = super().parameters(ensemble_member)
parameters["time_step_days"] = self.__day_steps

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For what is this parameter needed?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for highlight. parameter is not needed. I do not need to create time_step_days with __day_steps. Now I removed parameters method.

@tolga-akan

Copy link
Copy Markdown
Collaborator Author

@FJanssen-TNO Ready for reviewing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

15 minute timestepping

2 participants