Skip to content

Introduce new component from eesyplan - #492

Draft
Bachibouzouk wants to merge 203 commits into
mainfrom
feature/introduce-new-component
Draft

Bachibouzouk wants to merge 203 commits into
mainfrom
feature/introduce-new-component

Conversation

@Bachibouzouk

@Bachibouzouk Bachibouzouk commented Jul 8, 2026 •

Copy link
Copy Markdown

PROTOCOL (option a or b)

  1. a) write a new class which inherits from Asset with the new needed fields
    b) add the fields within the Asset class

  2. add an asset_type for this new component with their visible fields (under static/resources/assettypes_list.csv)

  3. add the asset to the drag and drop within the projects/views.py::scenario_create_topology function. Right at the beginning there is a dict named components with asset_type as keys and the verbose name as Value

  4. provide an icon for this component in static/asset/gui, its name must be <asset_type>.svg, like "commodity.svg" for example. You then need to add a mapping "<asset_type>:<asset_type>," within $component-categories-mapping in the static/scss/abstracts/_variables.scss

    At this stage the component will be visible within the GUI and can be dragged to the energy system. However option a) doesn't provide out of the box access to the component's fields, whereas option b) does.
    To change this one need to be able to set the model attribute of the Meta class to something else than Asset (ie a decorator function which would find the new asset's Model from a dict and return a CreateAssetForm instance with modified Meta

After internal disscussion and testing option a) seems the most long term beneficial, as it will make the components much more aligned on eesyplan structure. This PR already made the structural changes necessary for:

  • export a scenario to json and load it again within the GUI
  • export a scenario to a datapackage
  • duplicate a scenario using the GUI (clicking on the icon next to the scenario in the list of scenarios on the project display page)

Here is a list of the components which need to have their own Model (inheriting Asset class)

  • all the dso component (dso, gas_dso, h2_dso, heat_dso)
  • heat_pump (for this one the separate Model COPCalculator might need to be removed and added to the heat_pump interface)
  • chp
  • chp_fixed_ratio
  • electrolyzer

There is also the storage components (hess, h2ss, bess, gess), but the migration might be a bit more complex as they had a structure with a parent asset and 3 children assets

One need to look over clean() method from AssetCreateForm in forms.py to remove code which will not be necessary there anymore. Idem for the to_datapackage() method af the Asset class It will break the dto.py classes but this is only used for MVS and will be removed in the future.

Also look into widgets attribute of the Meta class attribute of the AssetCreateForm

Need to migrate the Storage into an eesyplan storage (this might require quite some preparation?)

To test the migrations I did setup a new database locally, initialised it from main branch (migration 0029). I added a projects from the OPT tool with all available assets. Then I switched to this branch and ran python manage.py migrate projects. I tested with python manage.py test_project_forms 1 that all the forms of this projects were loading without 404 error. Then I added a scenario with all the assets available at the 0075 migration (one need to update the asset types with python manage.py update_assettype --update . I then ran python manage.py migrate projects 0029, followed directly by python manage.py migrate projects and checked with python manage.py test_project_forms 2 that the second project with all assets still contained all assets (their values are reset the the default values though, but this is inavoidable)

@Bachibouzouk
Bachibouzouk requested a review from paulapreuss July 8, 2026 13:11
@Bachibouzouk
Bachibouzouk force-pushed the feature/introduce-new-component branch from b3b2e5d to fd1cf09 Compare July 13, 2026 14:02
@Bachibouzouk

Copy link
Copy Markdown
Author

Now export of the scenario produces an error but only when the scenario is reimported and the special component clicked

com = Commodity(asset_type=at, scenario=scen, full_load_hours_max=30)
com.save()
print(com.to_datapackage())
pdb.set_trace()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remove before merge (linter is already flagging this anyway so shouldn't be a problem)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

I would remove the whole file before merge, this is just for testing

Comment on lines +1048 to +1050
asset_type = ASSET_MAPPING.get(self.asset_type.asset_type, Asset)
existing_asset = get_object_or_404(asset_type, unique_id=self.unique_id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Why do we need to do this lookup for the asset within the model class? isn't existing_asset just self?

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ah, is this because Commodity is not treated as an Asset but as a separate class?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

If we use self within the Asset's methods, then self is of type Asset and I had the problem that I couldn't list the extra attributes

# 2) add an asset_type for this new component with their visible fields (under static/resources/assettypes_list.csv)


class Commodity(Asset):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I do like having the new component inherit from Asset rather than having a very bloated Asset class

Comment thread app/projects/forms.py Outdated


def get_asset_or_404(asset_type, asset_uuid):
asset_type = ASSET_MAPPING.get(asset_type, Asset)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Suggested change
asset_type = ASSET_MAPPING.get(asset_type, Asset)
asset_model = ASSET_MAPPING.get(asset_type, Asset)

I would rename this to match the variable name also used in asset_form_factory

Comment thread app/projects/forms.py Outdated
widget=forms.HiddenInput(), required=False, label=""
)

if self.asset_type_name == "heat_pump":

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ideally if we split the assets into their own models it would be good to also handle these special cases within the asset models. Or if the parameters have different names anyway depending on the asset (coming from the eesyplan naming), could also be handled through the general widget definition.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

We would not need to handle this as special cases because here we are overloading "efficiency" and using it as many different things. If we simply inheritate from Asset, then we write cop as attribute of the heat pump and do not need this whole if statement block :)

Comment thread app/projects/forms.py Outdated
return _AssetCreateForm(asset_type=asset_type, **kwargs)


class AssetCreateForm(OpenPlanModelForm):

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Delete if keeping the form factory

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This is just work in progress because of the nightmare StorageAssetForm which inherit from AssetForm. Hopefully we can get rid of the complicated StorageAsset with eesyplan :)

Comment thread app/resources/assettypes_list.csv Outdated
hess,energy_storage,Heat,storage,[name],kW (therm),"{'input_1':['bus_in_heat','Heat'],'output_1': ['bus_out_heat','Heat']}"
chp,energy_conversion,Electricity,extractionTurbineCHP,"[name,age_installed,installed_capacity,capex_fix,capex_var,opex_var,opex_fix,lifetime,optimize_cap,maximum_capacity,efficiency_multiple,efficiency,thermal_loss_rate]",kW,"{'input_1':['bus_in_fuel','Gas'],'output_1': ['bus_out_heat','Heat'], 'output_2': ['bus_out_electricity','Electricity']}"
chp_fixed_ratio,energy_conversion,Electricity,transformer,"[name,age_installed,installed_capacity,capex_var,opex_fix,lifetime,optimize_cap,maximum_capacity,efficiency_multiple,efficiency]",kW,"{'input_1':['bus_in_fuel','Gas'],'output_1': ['bus_out_heat','Heat'], 'output_2': ['bus_out_electricity','Electricity']}"
commodity,energy_production,Electricity,source,"[name,installed_capacity,capex_var,commodity_type,full_load_hours_max,full_load_hours_max_asset]",kW,"{'output_1': ['bus_out_electricity','Electricity']}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

How do we want to handle the commodity bus? Maybe we can just use the fuel bus for now?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This is why I started to implement the commodity. A quick solution is to do the same as with the busses in OpenPlan: we get 4 busses to choose from and we could get 4 commodities to choose from.

@Bachibouzouk
Bachibouzouk force-pushed the feature/introduce-new-component branch from d3f9747 to 3b207b1 Compare July 22, 2026 10:50
@Bachibouzouk
Bachibouzouk force-pushed the feature/introduce-new-component branch 2 times, most recently from 33b4d54 to a5e6479 Compare September 17, 2026 09:07
@github-actions

Copy link
Copy Markdown

Remember to describe your changes in the changelog!

@Bachibouzouk
Bachibouzouk force-pushed the feature/introduce-new-component branch 2 times, most recently from 2fe0efb to c34c4c8 Compare September 21, 2026 10:43
@Bachibouzouk
Bachibouzouk force-pushed the feature/introduce-new-component branch 6 times, most recently from c325282 to fb6b7ec Compare October 16, 2026 12:53
@Bachibouzouk
Bachibouzouk force-pushed the feature/introduce-new-component branch from 72f0eec to 68e97d8 Compare October 28, 2026 22:35
Bachibouzouk and others added 13 commits October 30, 2026 13:20
Inherting from Asset might be preferable, as the class remain a child of
Asset, one can always use Asset.objects.filter(asset_type=...)
The ModelForm is instanciated with a Meta class referring to the
specific asset model if differing from Asset. Currently problems remain
at the export to datapackage and export scenarios
And not always the default Asset class
Only the asset count of a given asset_type is relevant here
At those occasion it might be needed to make sure the classes inheriting
from Asset appear in the listing explicitely and not simply as Asset
instances.
This is useful to see that a migrated component still produces the same
dto which is sent to MVS
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
paulapreuss and others added 15 commits October 30, 2026 13:20
The eesyplan parameter got renamed multiple time, as they now have an
almost one to one mapping with the old name, the migrations files were
modified to make sure the data is correctly passed from the old to the
new field
The feedin_tariff is accessible for all DSOs,
it can only be array-like for electricity,
the feedin_cap is renamed maximum_feedin_capacity
and only concerns the electricity DSO
Use the asset_type explicitly and not a reference to the DB id
@Bachibouzouk
Bachibouzouk force-pushed the feature/introduce-new-component branch from 4196398 to a4c2ffa Compare October 30, 2026 12:21
Bachibouzouk and others added 14 commits October 30, 2026 14:22
I tihnk the error is related to these being the last dualinputfields so
the handling for the dynamic plotting isn't working (the upload does
work though). Not sure if it's really necessary to fix properly
currently.
This happen as the user clicks on the Compute COP button´
When the user clicks on the Manual tab or upload tab, then the graph
disappear, it reappears when the user clicks on the upload or select and
there is either an uploaded file or a selected timeseries.

There is still an error when the uploaded timeseries return an error,
the fieldwidget reselect the select tab although it should be on the
upload one, as this can be confusing otherwise
Fix COP calculator display and update to eesyplan method
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.

2 participants