Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: add gaussian blending to floris solutions in postprocess step (similar to UncertaintyInterface but in post-) #114

Merged

Conversation

Bartdoekemeijer
Copy link
Collaborator

This PR is ready to be merged.

Feature or improvement description
This PR adds a new function in floris_tools that allows users to apply Gaussian smearing on their df_fi_aprox in the wind direction axis. The results should be identical with FLORIS' UncertaintyInterface with fix_yaw_in_relative_frame=True, but then much faster because this is purely a post-processing step.

Related issue, if one exists
N/A

Impacted areas of the software
floris_tools

Additional supporting information
This PR allows the rapid generation of FLORIS solutions from an existing precalculated dataset with different values for wd_std. This can be helpful when tuning a model while including various levels of wd_std.

There are also a couple of small bug fixes in the code. Not the cleanest way of pulling them in like this, but figured it'll do the job okay since it's in the same functions/files.

Test results, if applicable
Here is a minimal example:

import numpy as np
from matplotlib import pyplot as plt

from flasc.floris_tools import (
    calc_floris_approx_table,
    add_gaussian_blending_to_floris_approx_table,
)
from flasc.examples.models import load_floris_artificial as load_floris

if __name__ == "__main__":
        # Load FLORIS object
        fi, _ = load_floris()

        # Get FLORIS approx. table
        df_fi_approx = calc_floris_approx_table(
            fi,
            wd_array=np.arange(0.0, 360.0, 3.0),
            ws_array=[8.0],
            ti_array=[0.08],
        )

        fig, ax = plt.subplots()
        ax.plot(df_fi_approx["wd"], df_fi_approx[[f"pow_{ti:03d}" for ti in range(7)]].sum(axis=1), label="Normal")

        # Apply Gaussian blending
        for wd_std in [1.0, 3.0, 10.0, 20.0]:
            df_fi_approx_gauss = add_gaussian_blending_to_floris_approx_table(df_fi_approx, wd_std=wd_std)
            ax.plot(df_fi_approx_gauss["wd"], df_fi_approx_gauss[[f"pow_{ti:03d}" for ti in range(7)]].sum(axis=1), label=f"Gaussian smeared (wd_std={wd_std:.1f} deg)")

        ax.grid(True)
        ax.set_xlabel("Wind direction (deg)")
        ax.legend()
        plt.show()

And produces:
image

@Bartdoekemeijer Bartdoekemeijer changed the title Feature: add gaussian blending in postprocess step (similar to UncertaintyInterface but in post-) Feature: add gaussian blending to floris solutions in postprocess step (similar to UncertaintyInterface but in post-) Aug 23, 2023
@paulf81
Copy link
Collaborator

paulf81 commented Aug 23, 2023

This looks good @Bartdoekemeijer , going to add to the 1.4 milestone,

@paulf81 paulf81 requested review from misi9170 and paulf81 August 23, 2023 16:08
@paulf81 paulf81 added the enhancement An improvement of an existing feature label Aug 23, 2023
@paulf81 paulf81 added this to the v1.4 milestone Aug 23, 2023
@@ -398,7 +408,7 @@ def calc_floris_approx_table(
solutions_dict["wd_{:03d}".format(turbi)] = \
wd_mesh.flatten() # Uniform wind direction
solutions_dict["ti_{:03d}".format(turbi)] = \
fi.floris.flow_field.turbulence_intensity_field[:, :, turbi, 0, 0].flatten()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks for fixing this Bart!

Copy link
Collaborator

@misi9170 misi9170 left a comment

Choose a reason for hiding this comment

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

Nice tool and looks good to me. I've approved, but @Bartdoekemeijer could you briefly explain the changes to floirs_tools.interpolate_floris_from_df_approx()? In particular:

  • Why the line that made sure "time" is dropped is commented out
  • The switch to only interpolating the "pow" column (not the others in varnames)

Happy to merge after that!

@Bartdoekemeijer
Copy link
Collaborator Author

Bartdoekemeijer commented Aug 28, 2023

Thanks for reviewing!

  • Why the line that made sure "time" is dropped is commented out

If the dataframe is large, the call reset_index slows the code down. I am now tackling a large dataset and found that this helps in speeding up the code. Also, I think we agreed that time should be just a column in df, not the index. So I guess I am forcing conventions a bit. Happy to revert if you experience issues with it.

  • The switch to only interpolating the "pow" column (not the others in varnames)

Are you referring to this line? We are still interpolating for each variable. The point is that when you call interpolate.RegularGridInterpolator, it calculates a triangulation between all the data points so that it can easily interpolate. This takes quite a bit of time for larger data tables. In the old code, we unnecessarily recalculate this triangulation for each varname. Now, knowing the triangulation is the same, I just updated the to-be-interpolated values through this line. The results should be identical between the old and new code, but the new code should be significantly faster.

@paulf81
Copy link
Collaborator

paulf81 commented Aug 28, 2023

If the dataframe is large, the call reset_index slows the code down. I am now tackling a large dataset and found that this helps in speeding up the code. Also, I think we agreed that time should be just a column in df, not the index. So I guess I am forcing conventions a bit. Happy to revert if you experience issues with it.

This is great I think, when I was originally mapping more of the code to polars, this was one of the changes I had to make (polars only uses simple indexes). I think a standard where time is just an index is a good one, it will also make grabbing polars speed up more broadly a smaller step.

@misi9170
Copy link
Collaborator

If the dataframe is large, the call reset_index slows the code down. I am now tackling a large dataset and found that this helps in speeding up the code. Also, I think we agreed that time should be just a column in df, not the index. So I guess I am forcing conventions a bit. Happy to revert if you experience issues with it.

This is great I think, when I was originally mapping more of the code to polars, this was one of the changes I had to make (polars only uses simple indexes). I think a standard where time is just an index is a good one, it will also make grabbing polars speed up more broadly a smaller step.

@paulf81 you mean a standard where time is just a column, right?

@misi9170
Copy link
Collaborator

Are you referring to this line? We are still interpolating for each variable. The point is that when you call interpolate.RegularGridInterpolator, it calculates a triangulation between all the data points so that it can easily interpolate. This takes quite a bit of time for larger data tables. In the old code, we unnecessarily recalculate this triangulation for each varname. Now, knowing the triangulation is the same, I just updated the to-be-interpolated values through this line. The results should be identical between the old and new code, but the new code should be significantly faster.

Ok that makes sense, figured it must be something like that but just couldn't quite connect the dots, thanks @Bartdoekemeijer! Proceeding to merge.

@misi9170 misi9170 merged commit 1401334 into NREL:develop Aug 28, 2023
@paulf81
Copy link
Collaborator

paulf81 commented Aug 28, 2023

If the dataframe is large, the call reset_index slows the code down. I am now tackling a large dataset and found that this helps in speeding up the code. Also, I think we agreed that time should be just a column in df, not the index. So I guess I am forcing conventions a bit. Happy to revert if you experience issues with it.

This is great I think, when I was originally mapping more of the code to polars, this was one of the changes I had to make (polars only uses simple indexes). I think a standard where time is just an index is a good one, it will also make grabbing polars speed up more broadly a smaller step.

@paulf81 you mean a standard where time is just a column, right?

yes, sorry!!

@Bartdoekemeijer Bartdoekemeijer deleted the feature/add_gauss_blur_to_df_approx branch August 29, 2023 07:15
@misi9170 misi9170 mentioned this pull request Oct 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement An improvement of an existing feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants