{"id":34591313,"url":"https://github.com/daggbt/pyedl","last_synced_at":"2026-05-27T06:02:15.199Z","repository":{"id":292526245,"uuid":"981167106","full_name":"daggbt/pyedl","owner":"daggbt","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-23T09:30:44.000Z","size":107,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-23T10:10:38.642Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/daggbt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-10T13:47:12.000Z","updated_at":"2026-04-23T09:29:42.000Z","dependencies_parsed_at":null,"dependency_job_id":"eabd4b92-1cbf-4cee-9ee6-da694578af28","html_url":"https://github.com/daggbt/pyedl","commit_stats":null,"previous_names":["daggbt/pycapapacitance","daggbt/pyedl"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/daggbt/pyedl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daggbt%2Fpyedl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daggbt%2Fpyedl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daggbt%2Fpyedl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daggbt%2Fpyedl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/daggbt","download_url":"https://codeload.github.com/daggbt/pyedl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/daggbt%2Fpyedl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33553127,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-27T02:00:06.184Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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-24T10:51:33.559Z","updated_at":"2026-05-27T06:02:15.189Z","avatar_url":"https://github.com/daggbt.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pyedl: Semianalytical Models for Electric Double Layers\n\n**pyedl** (formerly `pycapacitance`) is a Python package for modeling the physics of Electric Double Layers (EDL) in electrochemical systems. It implements semianalytical approximations for steric models (Carnahan-Starling and Liu) to efficiently calculate properties like electrode charge density, differential capacitance, and grand potential energies, particularly in regimes of high electrode potential and high electrolyte concentration where traditional dilute solution models fail.\n\nThis codebase accompanies the manuscript:\n\n\u003e **Semianalytical approximation of Ion Adsorption Layers and Capacitance in Carnahan–Starling-like steric models**  \n\u003e Dagmawi B. Tadesse and Drew F. Parsons  \n\u003e *Electrochimica Acta*, 531, 146266 (2025).  \n\u003e DOI: [10.1016/j.electacta.2025.146266](https://doi.org/10.1016/j.electacta.2025.146266)  \n\u003e URL: [ScienceDirect](https://www.sciencedirect.com/science/article/pii/S0013468625006279)\n\n## Features\n\n*   **Steric Models**: Implements the Carnahan-Starling (CS) and Liu equations of state for hard-sphere fluids within mean-field theory.\n*   **Composite Diffuse Layer (CDL)**: Implements a high-potential analytical approximation to the Bikerman model with a fully capped counterion concentration in the steric layer.\n*   **Double-Electrode Cells**: Compute full-cell voltage splits, capacitance, energies, and profiles from charge neutrality rather than user-supplied electrode potentials.\n*   **Semianalytical Approximation**: Uses a linear concentration profile approximation to solve the Poisson-Boltzmann equations analytically in the steric layer, providing rapid convergence to full numerical solutions at high potentials (\u003e0.2 V) and concentrations (\u003e1 M).\n*   **EDL Properties**:\n    *   **Charge Density**: Calculate electrode surface charge density ($\\sigma$).\n    *   **Differential Capacitance**: Calculate differential capacitance ($C_d$) with potential-dependent dielectric effects.\n    *   **Profiles**: Generate concentration, electric field, and potential profiles within the double layer.\n*   **Thermodynamics**:\n    *   **Grand Potential Energy**: Calculate the total energy stored in the EDL, decomposed into:\n        *   **Entropic Energy**: Ideal ion configuration entropy.\n        *   **Electrostatic Energy**: Energy stored in the electric field.\n        *   **Steric Energy**: Excess free energy due to finite ion size (excluded volume).\n*   **Material Database**: Includes extensible databases for common ions (alkali metals, halides, ionic liquids) and solvents (water, organic solvents).\n\n## Installation\n\nThe package requires Python 3.12+.\n\n### Using uv (Recommended)\n\n```bash\n# Clone the repository\ngit clone https://github.com/daggbt/pyedl.git\ncd pyedl\n\n# Run examples directly\nuv run examples/capacitance.py\nuv run examples/energy.py\nuv run examples/fitting.py\nuv run examples/double_electrode.py\n```\n\n### Using pip\n\n```bash\npip install .\n```\n\n## Usage\n\n### 1. Calculating Capacitance\n\n```python\nfrom pyedl import ion_database, solvent_database\nfrom pyedl import ElectrochemicalSystem, StericModel\n\n# Define the system: NaF in Water\nsystem = ElectrochemicalSystem(\n    cation=ion_database['Na+_hydrated'],\n    anion=ion_database['F-_hydrated'],\n    solvent=solvent_database['water'],\n    concentration=1.0,  # mol/L\n    temperature=298.15, # K\n    n_hydration_cation=3.5,\n    n_hydration_anion=2.7\n)\n\n# Initialize the model (Carnahan-Starling)\nmodel = StericModel(system, steric_model='cs')\n\n# Calculate capacitance at 1.0 V\npotential = 1.0 # V\ncapacitance = model.analytical_capacitance(potential)\nprint(f\"Capacitance at {potential}V: {capacitance:.2f} μF/cm²\")\n```\n\n### 2. Free Energy Analysis\n\nCalculate the components of the Grand Potential Energy stored in the EDL.\n\n```python\nfrom pyedl.materials import Ion, Solvent\nfrom pyedl import ElectrochemicalSystem, StericModel\n\n# Define custom materials (e.g., LiPF6 in Propylene Carbonate)\npc_solvent = Solvent(name='Propylene Carbonate', dielectricConstant=66.14, solventPolarizability=6.0)\nli_ion = Ion(name='Li+', charge=1, radiusAng=2.82, dispersionB=0.0, ionPolarizability=0.03)\npf6_ion = Ion(name='PF6-', charge=-1, radiusAng=2.54, dispersionB=0.0, ionPolarizability=4.0)\n\nsystem = ElectrochemicalSystem(\n    cation=li_ion, \n    anion=pf6_ion, \n    solvent=pc_solvent, \n    concentration=1.0\n)\n\nmodel = StericModel(system, steric_model='cs')\n\n# Calculate energy components at 1.0 V\nphi = 1.0\nentropic = model.get_entropic_energy(phi)\nelectrostatic = model.get_electrostatic_energy(phi)\nsteric = model.get_steric_free_energy(phi)\ntotal = model.get_total_energy(phi)\n\nprint(f\"Total Energy: {total:.4e} J/m²\")\nprint(f\"  - Entropic: {entropic:.4e} J/m²\")\nprint(f\"  - Electrostatic: {electrostatic:.4e} J/m²\")\nprint(f\"  - Steric: {steric:.4e} J/m²\")\n```\n\n### 3. Sampling and Plotting\n\nThe Phase 0 plotting API lives in `pyedl.plotting`, with the legacy root-level `pyedl.plot_capacitance_vs_potential` kept as a compatibility wrapper.\n\n```python\nfrom pyedl.plotting import (\n    plot_capacitance_vs_potential,\n    plot_energy_components_vs_potential,\n    sample_profiles,\n)\n\n# Plot capacitance vs potential and keep the sampled data\nfig, ax, capacitance_data = plot_capacitance_vs_potential(\n    system=system,\n    potential_range=(-1.5, 1.5),\n    save_path='capacitance_curve.png',\n)\n\n# Plot grand-potential components with the same public API style\nfig, ax, energy_data = plot_energy_components_vs_potential(\n    system=system,\n    potential_range=(0.1, 1.0),\n    save_path='energy_components.png',\n)\n\n# Sample steric-layer profiles without creating a figure\nprofile_data = sample_profiles(system=system, potential=0.8)\nprint(profile_data['steric_layer_thickness'])\n```\n\nIf you need the older two-array return shape, `pyedl.plot_capacitance_vs_potential(...)` still returns `(potentials, capacitance)`.\n\nFor complete runnable examples, see `examples/capacitance.py` and `examples/energy.py`.\n\n### 4. Fitting a Counterion Permittivity\n\nFor inversion or optimization workflows, the JIT sweep path can evaluate an ordered capacitance curve efficiently while scanning candidate parameters.\n\n```python\nimport numpy as np\nfrom pyedl import ion_database, solvent_database\nfrom pyedl import ElectrochemicalSystem, StericModel, fit_counterion_permittivity_curve\n\nsystem = ElectrochemicalSystem(\n    cation=ion_database['Na+_hydrated'],\n    anion=ion_database['F-_hydrated'],\n    solvent=solvent_database['water'],\n    concentration=1.0,\n    temperature=298.15,\n)\n\npotentials = np.linspace(0.02, 1.0, 251)\ntarget_model = StericModel(system, steric_model='cs')\nfit_model = StericModel(system, steric_model='cs')\n\n# Synthetic target curve for a positive-potential sweep.\ntarget_epsilon = 4.75\ntarget_model.ion_permitivities[1] = target_epsilon\ntarget_model.invalidate_caches()\ntarget_capacitance = target_model.analytical_capacitance_sweep_jit(potentials)\n\nfit_result = fit_counterion_permittivity_curve(\n    fit_model,\n    potentials,\n    target_capacitance,\n    epsilon_bounds=(1.0, 10.0),\n    use_jit_sweep=True,\n)\n\nprint(f\"Recovered permittivity: {fit_result.fitted_permittivity:.3f}\")\nprint(f\"Curve-fit RMSE: {fit_result.rmse:.3e} μF/cm²\")\n```\n\nFor a complete runnable example, see `examples/fitting.py`.\n\n### 5. Composite Diffuse Layer Approximation\n\nThe `CDLModel` provides the analytical composite diffuse layer approximation: below the steric threshold it follows the Gouy-Chapman branch, and above the threshold it uses a capped counterion layer matched to a diffuse tail.\n\n```python\nfrom pyedl import CDLModel\n\ncdl_model = CDLModel(system)\nphi = 1.0\n\nprint(cdl_model.get_steric_layer_thickness(phi))\nprint(cdl_model.charge_density(phi))\nprint(cdl_model.analytical_capacitance(phi))\nprint(cdl_model.get_total_energy(phi))\n```\n\nFor a complete comparison against the Carnahan-Starling model, see `examples/cdl.py`.\n\n### 6. Double-Electrode Full Cells\n\nFor a double-electrode cell, provide the full-cell voltage. The left and right electrode potentials are computed automatically from charge neutrality, so they should not be supplied by the user.\n\n```python\nfrom pyedl import CDLModel, DoubleElectrodeCell\n\nsingle_interface_model = CDLModel(system)\ncell = DoubleElectrodeCell(single_interface_model)\n\ncell_voltage = 1.0\nsplit = cell.get_potential_split(cell_voltage)\n\nprint(split.left_potential, split.right_potential)\nprint(split.left_charge_density + split.right_charge_density)\nprint(cell.analytical_capacitance(cell_voltage))\nprint(cell.get_energy_components(cell_voltage))\n```\n\n`DoubleElectrodeCell` works as a wrapper around single-interface models. It uses the analytical CDL split when available and otherwise solves the charge-neutrality equation directly, which also supports the semianalytical CS/Liu models.\n\nFor a complete runnable example, see `examples/double_electrode.py`.\n\n## Package Structure\n\n*   `pyedl.cells`: Full-cell wrappers and potential-split helpers.\n    *   `DoubleElectrodeCell`: Computes double-electrode voltage splits and combines single-interface observables.\n    *   `PotentialSplit`: Dataclass containing left/right electrode potentials and charge-neutrality residuals.\n*   `pyedl.models`: Core physics implementation.\n    *   `StericModel`: Implementation of Carnahan-Starling and Liu models.\n    *   `CDLModel`: Composite Diffuse Layer approximation with a capped counterion steric layer.\n    *   `ElectrochemicalSystem`: Container for system properties.\n*   `pyedl.materials`: Chemical property definitions.\n    *   `Ion`: Properties like radius, charge, polarizability.\n    *   `Solvent`: Dielectric constant, polarizability.\n*   `pyedl.fitting`: Inversion helpers for fitting counterion permittivities to capacitance curves.\n*   `pyedl.plotting`: Sampling and plotting helpers for capacitance, energy components, and steric-layer profiles.\n*   `pyedl.utils`: Data export helpers and compatibility wrappers for older plotting imports.\n\n## Citation\n\nIf you use this code in your research, please cite the following paper:\n\n```bibtex\n@article{TADESSE2025146266,\ntitle = {Semianalytical approximation of Ion Adsorption Layers and Capacitance in Carnahan–Starling-like steric models},\njournal = {Electrochimica Acta},\nvolume = {531},\npages = {146266},\nyear = {2025},\nissn = {0013-4686},\ndoi = {10.1016/j.electacta.2025.146266},\nurl = {https://www.sciencedirect.com/science/article/pii/S0013468625006279},\nauthor = {Dagmawi B. Tadesse and Drew F. Parsons},\nkeywords = {Carnahan–Starling equation, Steric forces, Semianalytical Carnahan–Starling approximations, Electric double layers, Electric double layer capacitors},\nabstract = {The Carnahan–Starling (CS) steric model is the best description of hard-sphere fluids within the mean-field theory. Here we introduce an approximation of the near-linear adsorption concentration profile of a counterion near an electrode for a CS model and derive the subsequent electric field and electrostatic potential profile in a double layer. This enables the derivation of a semianalytical approximation of the electrode charge density, differential capacitance, and total energies (grand potentials) of an electric double-layer capacitor. These semianalytical equations are valid for electrode potentials between 0.2–4 V and converge to the full numerical solutions of the CS model at high potentials of 1V and bulk concentration of 1M with relative errors less than 2% for the electrode charge densities, and less than 5% for the capacitance and total energies. We find the steric contribution comprises approximately one-quarter of the total energy at high electrode potentials, while the contribution from ideal ion entropies becomes insignificant. The model shows very good agreement with experimental measurements of an aqueous electrolyte, and good agreement at high potentials with computer simulations of an ionic liquid. These semianalytical approximations are effective for applications with concentrated solutions or ionic liquids at high applied voltages where the full numerical solution is computationally expensive or in some cases impossible.}\n}\n```\n\n## License\n\nMIT License\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaggbt%2Fpyedl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdaggbt%2Fpyedl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdaggbt%2Fpyedl/lists"}