{"id":34094758,"url":"https://github.com/mcsoini/symenergy","last_synced_at":"2026-04-10T10:32:31.195Z","repository":{"id":35169984,"uuid":"151922217","full_name":"mcsoini/symenergy","owner":"mcsoini","description":"Symbolic modelling of energy systems, based on SymPy.","archived":false,"fork":false,"pushed_at":"2022-12-27T15:35:15.000Z","size":1972,"stargazers_count":0,"open_issues_count":3,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-02-16T03:53:40.479Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mcsoini.png","metadata":{"files":{"readme":"README.rst","changelog":"changelog.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-10-07T08:48:14.000Z","updated_at":"2022-07-27T16:45:59.000Z","dependencies_parsed_at":"2023-01-15T15:10:41.435Z","dependency_job_id":null,"html_url":"https://github.com/mcsoini/symenergy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/mcsoini/symenergy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcsoini%2Fsymenergy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcsoini%2Fsymenergy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcsoini%2Fsymenergy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcsoini%2Fsymenergy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mcsoini","download_url":"https://codeload.github.com/mcsoini/symenergy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mcsoini%2Fsymenergy/sbom","scorecard":{"id":632623,"data":{"date":"2025-08-11","repo":{"name":"github.com/mcsoini/symenergy","commit":"a4ccf1e1a642aa38667c3cfcb9372da6eb54050f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":1.6,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: containerImage not pinned by hash: Dockerfile:1: pin your Docker image by updating jupyter/minimal-notebook to jupyter/minimal-notebook@sha256:1c4c8b6c7c27059c353d4e80523c2696e34723fde67d27418873ebeb42032551","Info:   0 out of   1 containerImage dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 2-Clause \"Simplified\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":0,"reason":"12 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2021-856 / GHSA-5545-2q6w-2gh6","Warn: Project is vulnerable to: GHSA-6p56-wp2h-9hxr","Warn: Project is vulnerable to: PYSEC-2019-108 / GHSA-9fq2-x9r6-wfmf","Warn: Project is vulnerable to: PYSEC-2021-857 / GHSA-f7c7-j99h-c22f","Warn: Project is vulnerable to: GHSA-fpfv-jqm9-f5jm","Warn: Project is vulnerable to: PYSEC-2020-73","Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5","Warn: Project is vulnerable to: PYSEC-2022-43012 / GHSA-r9hx-vwmv-q579","Warn: Project is vulnerable to: PYSEC-2018-34 / GHSA-2fc2-6r4j-p65h","Warn: Project is vulnerable to: PYSEC-2018-33 / GHSA-cw6w-4rcx-xphc","Warn: Project is vulnerable to: PYSEC-2017-1 / GHSA-frgw-fgh6-9g52"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-21T08:20:14.296Z","repository_id":35169984,"created_at":"2025-08-21T08:20:14.296Z","updated_at":"2025-08-21T08:20:14.296Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31638460,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-10T07:40:12.752Z","status":"ssl_error","status_checked_at":"2026-04-10T07:40:11.664Z","response_time":98,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-12-14T15:04:48.521Z","updated_at":"2026-04-10T10:32:31.183Z","avatar_url":"https://github.com/mcsoini.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"=============================\nSymEnergy \n=============================\n\nSymbolic modelling of energy systems, based on SymPy.\n\nSymEnergy provides a framework for the structured solution of cost-optimization of energy systems using \nthe standard Lagrange multiplier approach. The result consists in the close-form\nanalytical solutions to the optimization problem. For example, the energy production\nfrom a power plant is expressed as\na function of the vector of symbolic parameters. These solutions are evaluated\nfor certain parameters in order to identify relevant constraint combinations.\n\n============\nInstallation\n============\n\n``pip install symenergy``\n\n.. _label_example_minimal:\n\n`\u003chttps://pypi.org/project/SymEnergy/\u003e`_\n\n=============\nDocumentation\n=============\n\n`\u003chttps://symenergy.readthedocs.io/\u003e`_\n\n============\nPublication\n============\n\n  * \\M. C. Soini *et al.*, Does bulk electricity storage assist wind and solar in replacing dispatchable power production?, Energy Economics, `\u003chttps://doi.org/10.1016/j.eneco.2019.104495\u003e`_. \n  * \\M. C. Soini *et al.*, On the displacement of incumbent electricity storage by more efficient storage in a stylized market model,  Journal of Energy Storage, `\u003chttps://doi.org/ 10.1016/j.est.2022.105322\u003e`_. \n  * \\M. C. Soini, Systemic Interactions of Storage in the Power System, PhD Thesis, `\u003chttps://doi.org/10.13097/archive-ouverte/unige:146422\u003e`_. \n\n.. _label_example_minimal:\n\n===============\nMinimal example\n===============\n\nInvestigate the dispatch of two power plants \nduring a single time slot in dependence on decreasing residual load \n(increasing variable renewable energy production).\n\nInitialize a SymEnergy model instance:\n\n::\n\n    from symenergy.core import model\n    m = model.Model()\n\nAdd a time slot ``'t0'`` with 3000 load and 1 VRE production. VRE production \nis varied later; any finite value of this parameter is acceptable at this point to initialize the parameter.\n\n::\n\n    m.add_slot('t0', load=3000, vre=1)\n\nAdd two power plants: Cheap baseload power ``'n'`` with limited capacity, expensive peaker plants ``'g'`` with unconstrained power production:\n\n::\n\n    m.add_plant('n', vc0=1, capacity=1000)\n    m.add_plant('g', vc0=2)\n\nAll Lagrange problems corresponding to this model are generated and solved.\n\n::\n\n    m.generate_solve()\n\n\nAll results of this process are stored in the model attribute ``df_comb``, indexed by the *constraint combinations* (see below). The table below shows a single line of this table. It corresponds to the case where \n\n* the baseload plant is not producing power output (its positivity constraint is binding ``True``). \n* the baseload plant power production is not capacity-constrained (capacity constraint not binding ``False``) \n* the peaker plant output is not zero (non-binding positivity constraint ``False``)\n\n\n::\n    \n    m.df_comb.iloc[[0]].T \n\n    ===================  ==================================================================================================================================================\n    act_lb_n_pos_p_t0    True\n    act_lb_n_p_cap_C_t0  False\n    act_lb_g_pos_p_t0    False\n    lagrange             g_p_t0*vc0_g_none*w_none + lb_n_pos_p_t0*n_p_t0 + n_p_t0*vc0_n_none*w_none + pi_supply_t0*w_none*(-g_p_t0 + l_t0 - n_p_t0 - vre_scale_none*vre_t0)\n    variabs_multips      [g_p_t0, lb_n_pos_p_t0, n_p_t0, pi_supply_t0]\n    result               (-(-l_t0*w_none + vre_scale_none*vre_t0*w_none)/w_none, -(-vc0_g_none*w_none**2 + vc0_n_none*w_none**2)/w_none, 0, vc0_g_none)\n    tc                   -vc0_g_none*(-l_t0*w_none + vre_scale_none*vre_t0*w_none)\n    ===================  ==================================================================================================================================================\n\nThe ``lagrange`` value in the table above  corresponds to the Lagrange function constructed for this combination of active and inactive constraints. It is equal to the total cost (``g_p_t0*vc0_g_none*w_none + n_p_t0*vc0_n_none*w_none``), the equality constraint (energy balance/supply constraint ``-g_p_t0 + l_t0 - n_p_t0 - vre_scale_none*vre_t0`` with multiplier (shadow price) ``pi_supply_t0``), plus the only  binding constraint with the corresponding multiplier ``lb_n_pos_p_t0*n_p_t0``.\n\n\nThe ``variabs_multips`` are a list of all symbols/variables for which the problem was solved. In this case, these are the peaker plant power output ``g_p_t0``, the shadow price of the baseload power posivity constraint (``lb_n_pos_p_t0``), the baseload power production ``n_p_t0``, and the shadow price of the supply constraint (the \"electricity price\") ``pi_supply_t0``. The result column contains a list of the same variables and multipliers. Not surprisingly, the solution (not fully simplified) of the peaker power production is equal to the residual load ``l_t0 - vre_scale_none*vre_t0``; the electricity price is equal to the variable cost of peaker power production ``vc0_g_none``. The column ``tc`` is the total cost, generated by substituting the variable solutions into the total cost expression.\n\nThe SymEnergy evaluator calculates numerical results from the closed-form solutions for certain parameter values. This allows the identify the relevant constraint combinations. In the example below the model is evaluated for increasing VRE production: The value of the parameter ``vre`` of the time slot ``'t0'`` is varied in 31 steps between 0 and 3000 (residual load 0). \n\n::\n    \n    from symenergy.evaluator import evaluator\n    import numpy as np\n\n    x_vals_vre = {m.slots['t0'].vre: np.linspace(0, 3000, 31)}\n    ev = evaluator.Evaluator(m, x_vals=x_vals_vre)\n    ev.get_evaluated_lambdas_parallel()\n    ev.expand_to_x_vals_parallel()\n\nThe final results are stored in the attribute ``ev.df_exp``. The dataframe ``ev.df_bal`` is a convenient way of accessing the optimal solution's energy balance:\n\n::\n\n    (ev.df_bal.query('slot not in [\"global\"]')\n       .pivot_table(index='vre_t0', columns='func',\n                       values='lambd')[['n_p_t0', 'g_p_t0', 'vre_t0', 'l_t0']].plot.area())\n\n\n.. image:: minimal_balance.png\n    :align: center\n    :alt: minimal balance\n\n\nThe optimal solution thus corresponds to the case where the cheap baseload power plant produces power at maximum output, while the peaker plants cover the remaining residual load. Once the VRE production is large enough to fully replace the peaker plants, the production from baseload plants is reduced.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcsoini%2Fsymenergy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmcsoini%2Fsymenergy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmcsoini%2Fsymenergy/lists"}