Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ repos:
- id: ruff
args: ["--fix", "--show-fixes"]

- repo: https://github.com/python-jsonschema/check-jsonschema
rev: 0.36.0
hooks:
- id: check-jsonschema
name: Validate jobs YAML (schema)
args:
- "--schemafile"
- "data/jobs/schema.json"
files: "^data/jobs/.*\\.ya?ml$"
exclude: "^data/jobs/_TEMPLATE\\.ya?ml$"

# Spelling errors and typos
- repo: https://github.com/codespell-project/codespell
Expand Down
45 changes: 45 additions & 0 deletions assets/css/overrides.css
Copy link
Member

Choose a reason for hiding this comment

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

It looks like the code in this file was generated with AI. While we are okay with the use of AI-written code, we consider it your responsibility to thoroughly review it and address any potential mistakes. Could you please remove the comments indicative of AI and remove the redundant CSS rules from here?

Also, these styles will apply to the entire website, so we must ensure that they affect only the jobs page.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed and applied the requested clean up and scoping
scoped jobs styles to jobs page and removed ai indicative and verbose comments, also avoided unnecessary global impact, now job related rules are isolated under .jobs-board

Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,48 @@ content-container class */
.news-container, .hero-container {
width: 100%;
}

/* Admonitions: minor accessibility tweaks */
.adm { opacity: 1; }
.adm a { text-decoration: underline; }

@media (prefers-color-scheme: dark) {
/* prefer specificity over !important to avoid fighting the theme */
.article .adm, .article .adm *,
.content .adm, .content .adm *,
.markdown .adm, .markdown .adm * {
color: var(--text, #f1f5f9);
}
.adm a { color: var(--primary, #9ae6b4); }
.adm { background: var(--surface-2, rgba(255,255,255,0.06)); }
}
Comment on lines 56 to 61
Copy link
Member

Choose a reason for hiding this comment

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

Instead of !importants, we should address any dark theme problem upstream with the theme itself – I would advise against using them unless they're really needed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed, removed !important and used selector specificity as advised


/* Jobs board styles, scoped */
.jobs-board .job-card {
border: 1px solid var(--border, rgba(0,0,0,0.15));
padding: 1rem;
border-radius: 6px;
margin: 1rem 0;
background: var(--surface, transparent);
}
.jobs-board .job-card__header { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; }
.jobs-board .job-card__title { margin: 0; font-size: 1.15rem; }
.jobs-board .job-card__entity { color: var(--text-muted, inherit); font-weight: 600; }
.jobs-board .job-card__meta, .jobs-board .job-card__dates { display: flex; flex-wrap: wrap; gap: .5rem .5rem; margin: .5rem 0; }
.jobs-board .job-badge {
display: inline-flex;
align-items: center;
background: var(--surface-2, rgba(0,0,0,0.04));
border: 1px solid var(--border, rgba(0,0,0,0.15));
padding: .15rem .4rem;
border-radius: 999px;
font-size: .85rem;
color: var(--text, inherit);
margin-right: .5rem;
margin-bottom: .5rem;
}
.jobs-board .job-card__dates span { margin-right: .75rem; }
.jobs-board .job-card__description { margin: .5rem 0; color: inherit; line-height: 1.55; }
.jobs-board .job-card__description ul, .jobs-board .job-card__description ol { margin: .5rem 0 .5rem 1.25rem; }
.jobs-board .job-card__apply .button { display: inline-block; }
.jobs-board .job-card--archived { opacity: .85; }
3 changes: 2 additions & 1 deletion config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ title: "PyBaMM" # site title
theme: scientific-python-hugo-theme
relativeURLs: true
DefaultContentLanguage: en
disableKinds: ["term", "taxonomy"]
disableKinds: ["term", "taxonomy", "404"]
enableEmoji: true
enableInlineShortcodes: true


markup:
highlight:
noClasses: true
Expand Down
37 changes: 7 additions & 30 deletions content/jobs.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,13 @@ shortcutDepth: 0
summary: "Current job openings related to PyBaMM and battery modeling"
---

Welcome to the PyBaMM Jobs Board! Here you can find current job openings related to PyBaMM and battery modeling. If you're interested in contributing to the future of battery simulation and modeling, check out the opportunities below.
Welcome to the PyBaMM Jobs Board! Here you can find current job openings related to PyBaMM and battery modeling.

### Ionworks Open Position

**Location:** Remote (US- or UK-based)
</br>
**Type:** Full-time

Ionworks is always interested in connecting with talented individuals in the field of battery modeling and simulation. While we may not have specific positions open at the moment, we welcome expressions of interest from potential candidates who are passionate about advancing battery technology.

**Areas of Interest:**

- Battery modeling and simulation
- Software development for scientific applications

**Ideal Background:**

- Advanced degree (Masters or higher) in a relevant field (e.g., Chemical Engineering, Applied Mathematics, Physics)
- Experience with battery modeling software, preferably including PyBaMM
- Proficiency in Python programming
- Strong analytical and problem-solving skills
- Excellent communication and collaboration abilities

If you're excited about the prospect of contributing to cutting-edge battery simulation projects and shaping the future of energy storage technology, we encourage you to reach out. Your expression of interest will be kept on file for future opportunities that may arise.
{{< admonition tip >}}
To post a job, open a PR adding a file under data/jobs/ using the template at data/jobs/_TEMPLATE.yaml. See instructions below.
{{< /admonition >}}

<div style="border: 2px solid #000; text-align: center; padding: 10px; margin: 20px auto; max-width: 300px; background-color: #3776AB;">
<a href="mailto:hr@ionworks.com?subject=Ionworks%20open%20position%20(from%20PyBaMM%20jobs%20board)" class="button" style="color: white;">Express Interest</a>
</div>
{{< jobs-list >}}

---

Expand All @@ -48,13 +27,11 @@ Do you have an open position in battery modeling or simulation? By posting in th
- Increase visibility within the PyBaMM community and broader battery modeling ecosystem
- Support the open-source PyBaMM project and its community

Jobs can be posted by companies, research institutions, or individuals looking to hire for positions related to battery modeling and simulation. All fees collected for job postings will be used to support the development and maintenance of PyBaMM.
Jobs can be posted by companies, research institutions, or individuals looking to hire for positions related to battery modeling and simulation.

### How to Post a Job

1. [Email us](mailto:pybamm@pybamm.org) the job description (preferably as an editable document) or open a pull request adding your post.
2. Make the payment through [this link](https://app.hubspot.com/payments/purchase/hscs_lIGxEAJy1ZF1nSDuOswBBtgYJ2lqdM7yi40DttGAC8TMh9c8BUIptnqJAYMmllfq).
3. Optionally, add a **suggested donation** to further support PyBaMM’s mission.
To propose a listing, open a pull request adding a YAML file under data/jobs/ using data/jobs/_TEMPLATE.yaml. Submissions are validated automatically.

{{< admonition important >}}
For details, please review our [Terms & Conditions](/jobs-t-and-c/).
Expand Down
28 changes: 28 additions & 0 deletions data/jobs/_TEMPLATE.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Job posting template for the PyBaMM jobs board.
# Copy this file to a new name (e.g. acme-battery-modeler-20250315.yaml) and fill it in.
# Required keys: entity, title, url, percentTime, percentOSS, deadline, expires, location, description
# Notes: dates = YYYY-MM-DD; url starts with http(s); percentTime 1–100; percentOSS 0–100.

entity: Your Organisation
title: Battery Modeling Engineer (PyBaMM)
url: https://www.example.com/careers/battery-modeling-engineer
percentTime: 100
percentOSS: 50
deadline: 2026-01-31
expires: 2026-02-28
location: Remote (UTC±2 preferred)
tags: [full-time, PyBaMM, Python]
# author_date: 2025-12-01

description: |
One or two short paragraphs describing the role and team.

Responsibilities:
- Build, validate, and maintain physics-based battery models with PyBaMM
- Parameterise models, run studies, and analyse results
- Collaborate with the open-source community where appropriate

Requirements:
- Strong Python and numerical methods
- Experience with physics-based battery modeling or electrochemistry
- Clear communication and collaboration
22 changes: 22 additions & 0 deletions data/jobs/example-company-battery-modeler-20251222.yaml
Copy link
Member

Choose a reason for hiding this comment

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

Let's use the existing Ionworks example here and include it, instead of Example Company.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

addressed, replaced the example with Ionworks example

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
entity: Ionworks
title: Battery Modeling Engineer (PyBaMM)
url: https://www.ionworks.com/
percentTime: 100
percentOSS: 50
deadline: 2026-01-31
expires: 2026-02-28
location: Remote (UK/EU time zones preferred)
tags: [full-time, modeling, PyBaMM, Python]
description: |
Ionworks is looking for a Battery Modeling Engineer to build and deploy
physics-based battery models using PyBaMM for clients across industry and academia.

Responsibilities:
- Develop, validate, and maintain battery models using PyBaMM
- Parameterise models, run simulations, and analyse results for production use
- Collaborate with open-source maintainers and contribute improvements back to PyBaMM where appropriate

Requirements:
- Strong Python experience and familiarity with numerical methods
- Experience with physics-based battery modelling and scientific computing
- Excellent communication and collaboration skills
70 changes: 70 additions & 0 deletions data/jobs/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "PyBaMM Jobs Board Posting",
"type": "object",
"additionalProperties": false,
"required": [
"entity",
"title",
"url",
"percentTime",
"percentOSS",
"deadline",
"expires",
"location",
"description"
],
"properties": {
"entity": {
"type": "string",
"minLength": 1
},
"title": {
"type": "string",
"minLength": 1
},
"url": {
"type": "string",
"minLength": 1,
"pattern": "^https?://"
},
"percentTime": {
"type": "integer",
"minimum": 1,
"maximum": 100
},
"percentOSS": {
"type": "integer",
"minimum": 0,
"maximum": 100
},
"deadline": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"expires": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"author_date": {
"type": "string",
"pattern": "^\\d{4}-\\d{2}-\\d{2}$"
},
"location": {
"type": "string",
"minLength": 1
},
"tags": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true
},
"description": {
"type": "string",
"minLength": 1
}
}
}
54 changes: 54 additions & 0 deletions layouts/partials/jobs/card.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{{/* Renders a single job using theme shortcodes (card, badge, button). Expects dict with keys: job, now */}}
{{- $job := .job -}}
{{- $now := .now -}}
{{- $open := or (not $job.expires) (ge (time $job.expires) $now) -}}

{{- $scratch := newScratch -}}

{{/* Build badges using theme badge shortcode */}}
{{- with $job.location -}}
{{- $scratch.Add "badges" (printf "{{< badge secondary >}}%s{{< /badge >}} " .) -}}
{{- end -}}
{{- with $job.percentTime -}}
{{- $scratch.Add "badges" (printf "{{< badge primary >}}%d%% time{{< /badge >}} " .) -}}
{{- end -}}
{{- with $job.percentOSS -}}
{{- $scratch.Add "badges" (printf "{{< badge success >}}%d%% OSS{{< /badge >}} " .) -}}
{{- end -}}
{{- with $job.tags -}}
{{- range . -}}
{{- $scratch.Add "badges" (printf "{{< badge muted >}}%s{{< /badge >}} " .) -}}
{{- end -}}
{{- end -}}
{{- $badges := $scratch.Get "badges" | default "" -}}

{{/* Dates summary */}}
{{- $dates := "" -}}
{{- with $job.deadline -}}
{{- $dates = printf "%s\n- Deadline: %s" $dates . -}}
{{- end -}}
{{- with $job.expires -}}
{{- $dates = printf "%s\n- Visible until: %s" $dates . -}}
{{- end -}}

{{/* Optional apply button */}}
{{- $apply := "" -}}
{{- with $job.url -}}
{{- $apply = printf "\n\n{{< button style=\"primary\" label=\"Apply / Learn more\" link=\"%s\" >}}" . -}}
{{- end -}}

{{/* Card class for archived */}}
{{- $classcard := "" -}}
{{- if not $open -}}
{{- $classcard = "sd-opacity-75" -}}
{{- end -}}

{{- $body := printf "%s\n\n%s\n\n%s%s" ($job.entity | default "") $badges ($job.description | default "") $apply -}}
{{- $card := printf "{{< card >}}\n%s\n%s\n%s\n%s\n{{< /card >}}"
(printf "title = '%s'" ($job.title | default ""))
(cond (ne $classcard "") (printf "classcard = '%s'" $classcard) "")
(printf "body = '''\n%s\n%s\n'''" ($body | replaceRE "'" "\\'"))
(cond (and $job.url (ne $job.url "")) (printf "link = '%s'" $job.url) "")
-}}

{{ .Page.RenderString $card }}
56 changes: 56 additions & 0 deletions layouts/partials/jobs/list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{{/*
Lists jobs from data/jobs. Splits into open and archived by expires date.
Sorts open by deadline asc; archived by expires desc.
*/}}
{{- $now := now -}}
{{- $jobs := slice -}}

{{/* Load YAML job postings directly from data/jobs */}}
{{- range (readDir "data/jobs") -}}
{{- if and (not .IsDir) (or (hasSuffix .Name ".yaml") (hasSuffix .Name ".yml")) (ne .Name "_TEMPLATE.yaml") (ne .Name "schema.json") -}}
{{- $path := printf "data/jobs/%s" .Name -}}
{{- $data := (readFile $path | transform.Unmarshal) -}}
{{- $key := replaceRE "\\.(yaml|yml)$" "" .Name -}}
{{- $job := (dict "key" $key) | merge $data -}}
{{- $jobs = $jobs | append $job -}}
{{- end -}}
{{- end -}}

{{/* partition */}}
{{- $open := slice -}}
{{- $archived := slice -}}
{{- range $jobs -}}
{{- $exp := .expires -}}
{{- if or (not $exp) (ge (time $exp) $now) -}}
{{- $open = $open | append . -}}
{{- else -}}
{{- $archived = $archived | append . -}}
{{- end -}}
{{- end -}}

{{- $sortedOpen := sort $open "deadline" "asc" -}}

<h2 id="open-roles">Open roles</h2>
{{- if gt (len $sortedOpen) 0 -}}
{{- range $sortedOpen -}}
{{ partial "jobs/card.html" (dict "job" . "now" $now) }}
{{- end -}}
{{- else -}}
<p>No open roles at the moment.</p>
{{- end -}}

<hr/>

{{- $sortedArchived := sort $archived "expires" "desc" -}}
{{- $body := "" -}}
{{- if gt (len $sortedArchived) 0 -}}
{{- $scratch := newScratch -}}
{{- range $sortedArchived -}}
{{- $scratch.Add "html" (partial "jobs/card.html" (dict "job" . "now" $now)) -}}
{{- end -}}
{{- $body = $scratch.Get "html" -}}
{{- else -}}
{{- $body = "<p>No archived roles yet.</p>" -}}
{{- end -}}
{{- $md := printf "{{< details \"%s\" >}}\n%s\n{{< /details >}}" "Archived roles" $body -}}
{{ .Page.RenderString $md }}
4 changes: 4 additions & 0 deletions layouts/shortcodes/jobs-list.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{{/* Shortcode to render the jobs list from data/jobs */}}
<div class="jobs-board">
{{ partial "jobs/list.html" . }}
</div>