diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4300cb2..bde84f5 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -17,6 +17,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v4 + with: + submodules: 'true' - uses: actions/setup-python@v6 with: diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..265efe5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/Summer-school-Intro-Git"] + path = src/Summer-school-Intro-Git + url = git@github.com:Cambridge-ICCS/Summer-school-Intro-Git.git diff --git a/exercises/dependencies_exercises.qmd b/exercises/dependencies_exercises.qmd index 443debc..12b5bde 100644 --- a/exercises/dependencies_exercises.qmd +++ b/exercises/dependencies_exercises.qmd @@ -39,9 +39,7 @@ https://docs.xarray.dev/en/stable/getting-started-guide/installing.html - lapack library - blas library - sqlite -- curl - glibc -- gcc/gfortran - mpdecimal - libffi - ... diff --git a/exercises/problem/climate_model.py b/exercises/problem/climate_model.py new file mode 100644 index 0000000..d791bdc --- /dev/null +++ b/exercises/problem/climate_model.py @@ -0,0 +1,15 @@ +solar_constant = 1370 +sigma = 5.67e-8 # Stefan-Boltzmann constant + +def absorbed_solar_radiation(albedo): + return solar_constant*(1-albedo)/4 + +def emitted_radiation(emissivity, temperature): + return emissivity * sigma * temperature**4 + +def energy_balanced_temperature(emissivity, albedo): + # dT/dt = 0 => in = out + return (solar_constant*(1-albedo)/(4*emissivity * sigma))**0.25 + +def emissivity_given_temp(albedo, temperature): + return solar_constant*(1-albedo)/(4*sigma*temperature**4) diff --git a/exercises/problem/plot4.py b/exercises/problem/plot4.py new file mode 100644 index 0000000..afa599a --- /dev/null +++ b/exercises/problem/plot4.py @@ -0,0 +1,25 @@ +import climate_model + +import xarray +import matplotlib.pyplot as plt + +global_ds = xarray.open_dataset("../data/HadCRUT.5.0.0.0_analysis_summary-series_global_annual.nc") + +fig, axs = plt.subplots(1, 1, figsize=(10,6), layout='constrained') + +# Absolute mean temperature between 1961 and 1990 +# https://crudata.uea.ac.uk/cru/data/temperature/abs_glnhsh.txt +absolute_value = 13.974 + 273.5 +time = global_ds['time'].data +temperature = global_ds['tas_mean'].data + absolute_value +albedo = 0.3 + +epsilon = climate_model.emissivity_given_temp(albedo, temperature) + +axs.plot(time, epsilon) + +axs.set_xlabel("Year") +axs.set_ylabel("Effective emissivity of Earth") + +plt.show() + diff --git a/exercises/testing_exercises.qmd b/exercises/testing_exercises.qmd new file mode 100644 index 0000000..eba8a7b --- /dev/null +++ b/exercises/testing_exercises.qmd @@ -0,0 +1,13 @@ +## Exercises + +In the example repository, there is a file called 'climate_model.py'. +This file contains some functions that are used in 'plot4.py' + +Task: + +1. Write some basic tests for these functions (think about inputs that give known + outputs) +2. Think about what properties/behaviours these functions should have, and write + tests for them +3. Look at the other python files, and see if any functions can be extracted and + tested diff --git a/flake.lock b/flake.lock index aef794c..946251c 100644 --- a/flake.lock +++ b/flake.lock @@ -1,56 +1,25 @@ { "nodes": { - "flake-utils": { - "inputs": { - "systems": "systems" - }, + "nixpkgs": { "locked": { - "lastModified": 1731533236, - "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "lastModified": 1792502884, + "narHash": "sha256-IoNisKcGbUjdd45qCqywGMCYmZ5EnkxezvLII0FWwNA=", + "owner": "Nixos", + "repo": "nixpkgs", + "rev": "02c087f3fe673c9e317f206a627cb6b910336dbe", "type": "github" }, "original": { - "owner": "numtide", - "repo": "flake-utils", + "owner": "Nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", "type": "github" } }, - "nixpkgs": { - "locked": { - "lastModified": 1783915482, - "narHash": "sha256-w9ktuEgDIWGsX58tR3nI5HBGNy1idO8KY4urO3msko0=", - "rev": "6cdc7fc76e8bf7fde9fa43a849fcaaa70e230dee", - "type": "tarball", - "url": "https://releases.nixos.org/nixpkgs/nixpkgs-26.11pre1033616.6cdc7fc76e8b/nixexprs.tar.xz" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, "root": { "inputs": { - "flake-utils": "flake-utils", "nixpkgs": "nixpkgs" } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 13d53ec..b1323de 100644 --- a/flake.nix +++ b/flake.nix @@ -1,14 +1,40 @@ { description = "Reproducibility in Scientific Software environment"; - - inputs.flake-utils.url = "github:numtide/flake-utils"; - - outputs = { self, nixpkgs, flake-utils }: - flake-utils.lib.eachDefaultSystem - (system: - let pkgs = nixpkgs.legacyPackages.${system}; in - { - devShells.default = import ./shell.nix { inherit pkgs; }; - } - ); + inputs = { + nixpkgs.url = "github:Nixos/nixpkgs/nixos-unstable"; + }; + outputs = { self, nixpkgs }: + let + system = "x86_64-linux"; + pkgs = nixpkgs.legacyPackages.${system}; + myPythonPackages = ps: with ps; [ + pandas + numpy + matplotlib + jupyter + jupyter-cache + ]; + pythonEnv = pkgs.python3.withPackages myPythonPackages; + in + { + devShells.${system}.default = pkgs.mkShell { + packages = [ + ((pkgs.quarto.override { + extraPythonPackages = myPythonPackages; + }).overrideAttrs (oldAttrs: { + # Remove this overrideAttrs patch when fixed. + # See https://github.com/NixOS/nixpkgs/issues/519484#issuecomment-4667477454 + postPatch = (oldAttrs.postPatch or "") + '' + substituteInPlace bin/quarto.js \ + --replace-fail "syntax-highlighting" "highlight-style" + ''; + })) + pythonEnv + ]; + shellHook = '' + echo "Quarto Environment Active (Pure Flake)" + echo "Quickstart: run 'quarto render document.qmd'" + ''; + }; + }; } diff --git a/shell.nix b/shell.nix deleted file mode 100644 index 6fd05cb..0000000 --- a/shell.nix +++ /dev/null @@ -1,14 +0,0 @@ -{ pkgs ? import { } }: -pkgs.mkShell { - packages = [ - pkgs.quarto - (pkgs.python3.withPackages (python-pkgs: with python-pkgs; [ - # select Python packages here - pandas - numpy - matplotlib - jupyter - jupyter-cache - ])) - ]; -} diff --git a/src/Summer-school-Intro-Git b/src/Summer-school-Intro-Git new file mode 160000 index 0000000..1a5cba2 --- /dev/null +++ b/src/Summer-school-Intro-Git @@ -0,0 +1 @@ +Subproject commit 1a5cba2778f027d3058aa9563fd35ed46d7774df diff --git a/src/_extensions/quarto-ext/attribution/_extension.yml b/src/_extensions/quarto-ext/attribution/_extension.yml new file mode 100644 index 0000000..2da3ff6 --- /dev/null +++ b/src/_extensions/quarto-ext/attribution/_extension.yml @@ -0,0 +1,14 @@ +title: Attribution +author: Roland Schmehl +version: 0.1.1 +quarto-required: ">=1.2.198" +contributes: + revealjs-plugins: + - name: RevealAttribution + script: + - attribution.js + stylesheet: + - attribution.css + + + diff --git a/src/_extensions/quarto-ext/attribution/attribution.css b/src/_extensions/quarto-ext/attribution/attribution.css new file mode 100644 index 0000000..d601221 --- /dev/null +++ b/src/_extensions/quarto-ext/attribution/attribution.css @@ -0,0 +1,19 @@ +/* Attribution plugin: text along the right edge of the viewport */ +.attribution{ + position: absolute; + top: 50%; + bottom: auto; + left: 50%; + right: auto; + font-size: 0.4em; + pointer-events: none; + text-align: center; + writing-mode: vertical-lr; + transform: translate( -50%, -50% ) scale( 100% ) rotate(-180deg); + text-orientation: sideways; +} + +/* Attribution plugin: activate pointer events for attribution text only */ +.attribution .content{ + pointer-events: auto; +} diff --git a/src/_extensions/quarto-ext/attribution/attribution.js b/src/_extensions/quarto-ext/attribution/attribution.js new file mode 100644 index 0000000..c0fc5b1 --- /dev/null +++ b/src/_extensions/quarto-ext/attribution/attribution.js @@ -0,0 +1,75 @@ +/***************************************************************** +** Author: Roland Schmehl, r.schmehl@tudelft.nl +** +** A plugin for displaying attribution texts sideways along the right +** edge of the viewport. When resizing the viewport or toggling full +** screen mode, the attribution text sticks persistently to the right +** edge of the viewport. +** +** The dynamic scaling of the attribution text via CSS transform +** is adopted from the fullscreen plugin. +** +** Version: 1.0 +** +** License: MIT license (see file LICENSE) +** +******************************************************************/ + +window.RevealAttribution = window.RevealAttribution || { + id: 'RevealAttribution', + init: function(deck) { + initAttribution(deck); + } +}; + +const initAttribution = function(Reveal){ + +var ready = false; +var resize = false; +var scale = 1; + +window.addEventListener( 'ready', function( event ) { + + var content; + + // Remove configured margin of the presentation + var attribution = document.getElementsByClassName("attribution"); + var width = window.innerWidth; + var configuredWidth = Reveal.getConfig().width; + var configuredHeight = Reveal.getConfig().height; + + scale = 1/(1-Reveal.getConfig().margin); + + for (var i = 0; i < attribution.length; i++) { + content = attribution[i].innerHTML; + attribution[i].style.width = configuredWidth + "px"; + attribution[i].style.height = configuredHeight + "px"; + attribution[i].innerHTML = "" + content + ""; + attribution[i].style.transform = 'translate( -50%, -50% ) scale( ' + scale*100 + '% ) rotate(-180deg)'; + } + + // Scale with cover class to mimic backgroundSize cover + resizeCover(); + +}); + +window.addEventListener( 'resize', resizeCover ); + +function resizeCover() { + + // Scale to mimic backgroundSize cover + var attribution = document.getElementsByClassName("attribution"); + var xScale = window.innerWidth / Reveal.getConfig().width; + var yScale = window.innerHeight / Reveal.getConfig().height; + var s = 1; + + if (xScale > yScale) { + // The div fits perfectly in x axis, stretched in y + s = xScale/yScale; + } + for (var i = 0; i < attribution.length; i++) { + attribution[i].style.transform = 'translate( -50%, -50% ) scale( ' + s*scale*100 + '% ) rotate(-180deg)'; + } +} + +}; diff --git a/src/_pytest.qmd b/src/_pytest.qmd new file mode 100644 index 0000000..71888cb --- /dev/null +++ b/src/_pytest.qmd @@ -0,0 +1,159 @@ +# Testing with pytest + +## What is pytest? + +:::{.columns} +::::{.column width=50%} +- A testing *framework* for python +- Makes it a lot easier to write tests +- Is used extensively by python packages +- Automatically discovers and runs tests +:::: +::::{.column width=50%} +![](images/pytest.png){style="width:50%;"} +:::: +::: + +## pytest basics + +\ + +- Tests are .py files and live in a `tests/` directory +- Each test group is a function with prefix `test_` +- Use the `assert` keyword to validate an expression is true + +\ + +:::{.columns} +::::{.column width=30%} +```{.python filename="src/add.py"} +def add(a, b): + return a+b +``` +```{.python filename="tests/test.py"} +def test_add(): + assert add(0, 0) == 0 + assert add(1, 0) == 1 + assert add(0, 1) == 1 + assert add(1, 1) == 2 + ... +``` +:::: +::::{.column width=70%} + +```{=html} +
terminal
+
+===================================== test session starts ===================================== +platform linux -- Python 3.14.7, pytest-9.1.1, pluggy-1.6.0 +rootdir: /tmp/example +collected 1 item +  +tests/test.py . [100%] +  +====================================== 1 passed in 0.00s ====================================== +
+``` +:::: +::: + +## pytest basics + +What if we implemented `add` wrong? + +```{.python filename="src/add,py"} +def add(a, b): + return a-b # Incorrect +``` + +\ + +```{=html} +
+[jack@nixos:~]$ pytest tests/test.py +platform linux -- Python 3.14.7, pytest-9.1.1, pluggy-1.6.0 +rootdir: /tmp/example +collected 1 item +  +tests/test.py F [100%] +  +========================================== FAILURES =========================================== +__________________________________________ test_add ___________________________________________ +  + def test_add(): + assert add(0, 0) == 0 + assert add(1, 0) == 1 +> assert add(0, 1) == 1 +E assert -1 == 1 +E + where -1 = add(0, 1) +  +tests/test.py:7: AssertionError +=================================== short test summary info =================================== +FAILED tests/test.py::test_add - assert -1 == 1 +====================================== 1 failed in 0.02s ====================================== +
+``` + +## Parametrized tests + +- pytest implements a lot of useful tools to make writing tests easier +- One of these is test parametrization, which allows us to reuse tests for different + inputs +- We only need to give the `pytest.mark.parametrize` decorator: + - The names of the input variables + - A list of tuples of inputs + +```{.python filename="tests/test.py"} +@pytest.mark.parametrize("x,y,expected", [(0, 0, 0), (1, 0, 1), (0, 1, 1), (1, 1, 2)]) +def test_add(x, y, expected): + assert add(x, y) == expected +``` + +## What to test + +- Beyond using fixed points, we can think about how a function should behave +- For example, our add function should have the following *properties* + - `add(x,0) == x` + - `add(x, y) == add(y, x)` + - `add(x, add(y, z)) == add(add(x, y), z)` + +## Writing code for unit testing + +:::{.columns} +::::{.column width=50%} + +- Unit testing forces us to write code that is minimal +- Decompose functions into their smallest logical unit +- Smaller functions are easier to test (and review!) + - Fewer/simpler inputs + - Can help to think of edge cases +:::: +::::{.column width=50%} + +Easier to test this: +```{.python} +def complicated_computation(data): + z = computation_1(data.x, data.y) + return computation_2(data.t, data.w, z) + +def computation_1(x, y): + result = atan2(x, y) + # Maybe do something else here + return result + +def computation_2(t, w, z): + result = exp((w+z)/t) + # Maybe do something else here + return result +``` +Than this: +```{.python} +def complicated_computation(data): + z = atan2(data.x, data.y) + z = ... + result = exp((data.w+z)/data.t) + result = ... + return result +``` +:::: +::: diff --git a/src/automation.qmd b/src/automation.qmd index 9112284..088ed80 100644 --- a/src/automation.qmd +++ b/src/automation.qmd @@ -28,11 +28,24 @@ There are many benefits to automating workflows: ## Automation and reproducibility +:::{.columns} +::::{.column width=40%} - Automating workflows tracks how research artifacts were actually produced - - Makes it easier for others to use and verify our work - - Results are more trustworthy +:::: +::::{.column width=60%} +```{mermaid} +flowchart TB + I[Load Data] --> A[Compute A] + I --> B[Compute B] + B --> C[Compute C] + A --> D[Produce Plot] + B --> E[Produce Plot] + C --> F[Produce Plot] +``` +:::: +::: ## How to automate @@ -49,3 +62,13 @@ There are many benefits to automating workflows: - Not as easy to invoke external programs - Scripts should be written like any other code! + +## Workflow engines + +- Sometimes workflows become more complicated than a script can handle +- Workflow engines allow you to declare your workflow, and then handle running it +- Some can also handle submitting HPC jobs (check your HPC docs/sysadmins first!) +- Examples: + - Snakemake + - Cylc + - Common Workflow Language (CWL) implementations diff --git a/src/custom.scss b/src/custom.scss index f5dff29..fd3aa3a 100644 --- a/src/custom.scss +++ b/src/custom.scss @@ -1,9 +1,411 @@ /*-- scss:defaults --*/ +// FONTS +@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@500;600;700&display=swap'); + +$presentation-heading-font: 'Montserrat', sans-serif; + +$accent: #0c4e8a; +/*-- scss:rules --*/ + +// Title and headings styling +#title-slide { + text-align: center; + + .title { + font-family: $presentation-heading-font; + font-weight: 400; + font-size: 2.5em; + } + + .subtitle { + color: $accent; + font-style: italic; + } + + .author, + .quarto-title-author-name { + color: $body-color; + font-size: 1.2em; + } + + .quarto-title-authors { + display: flex; + justify-content: center; + flex-direction: row; // Ensure horizontal layout + flex-wrap: wrap; + gap: 2em; // Space between authors + // display: flex; + // flex-direction: row; + // flex-wrap: wrap; + + .quarto-title-author { + padding-left: 0em; + padding-right: 0em; + width: auto; // Allow variable width based on content + max-width: 30%; // Limit width so multiple fit on one row + flex: 0 0 auto; // Don't grow or shrink + } + } + + .institute, + .quarto-title-affiliation, + .quarto-title-author-email { + font-style: italic; + font-size: 80%; + // color: #fffafa; + } + + .date { + font-weight: 400; // Set your desired font weight (100-900) + font-size: 1em; // Optionally adjust the size + color: $body-color; // Use the default text color or set your own + margin-top: 1em; // Add some space above the date + } + + +} + +// Control heading size and weight for non-title slides +.reveal h1:not(#title-slide h1) { + font-size: 2.0em; + font-weight: 600; +} + +.reveal h2:not(#title-slide h2) { + font-size: 1.7em; + font-weight: 550; +} + +.reveal h3:not(#title-slide h3) { + font-size: 1.3em; + font-weight: 500; +} + +$presentation-header-margin: 5%; + $presentation-font-size-root: 1.5em; $presentation-line-height: 1.5em; -ul { +/*-- scss:rules --*/ + +.reveal .slide .li { + margin-top: 1em; +} + +/*-- vertically center columns (or any container) --*/ +.v-center-container { display: flex; + justify-content: center; align-items: center; + height: 90%; +} + +.reveal .left-column ul { + padding-right: 0.5em; +} + +.reveal .right-column ul { + margin-left: 1.25em; +} + +.term-container { + background: #171717; + border-radius: 5px; + border-color: white; + color: white; + word-break: break-word; + overflow-wrap: break-word; + font-family: "SFMono-Regular", Monaco, Menlo, Consolas, "Liberation Mono", Courier, monospace; + font-size: 12px; + line-height: 20px; + white-space: pre-wrap; +} + +.term-container img { max-width: 100%; } + +.term-container time { padding-right: 1ex; } + +.term a { color: inherit; text-decoration: underline; text-decoration-style: dashed; } +.term a:hover { color: #2882F9 } + +@keyframes blink-animation { + to { + visibility: hidden; + } } + +.term-fg1 { } /* don't bold beccause it looks weird */ +.term-fg2 { color: #838887; } /* faint (decreased intensity) - same as gray really */ +.term-fg3 { font-style: italic; } /* italic */ +.term-fg4 { text-decoration: underline; } /* underline */ +.term-fg5 { animation: blink-animation 1s steps(3, start) infinite; } /* blink */ +.term-fg9 { text-decoration: line-through; } /* crossed-out */ + +.term-fg30 { color: #666666; } /* black (but we can't use black, so a diff color) */ +.term-fg31 { color: #ff7070; } /* red */ +.term-fg32 { color: #b0f986; } /* green */ +.term-fg33 { color: #c6c502; } /* yellow */ +.term-fg34 { color: #8db7e0; } /* blue */ +.term-fg35 { color: #f271fb; } /* magenta */ +.term-fg36 { color: #6bf7ff; } /* cyan */ + +/* high intense colors */ +.term-fgi1 { color: #5ef765; } +.term-fgi90 { color: #838887; } /* grey */ +.term-fgi91 { color: #ff3333; } /* red */ +.term-fgi92 { color: #00FF00; } /* green */ +.term-fgi93 { color: #fffc67; } /* yellow */ +.term-fgi94 { color: #6871ff; } /* blue */ +.term-fgi95 { color: #ff76ff; } /* magenta */ +.term-fgi96 { color: #60fcff; } /* cyan */ + +/* background colors */ +.term-bg40 { background: #676767; } /* grey */ +.term-bg41 { background: #ff4343; } /* red */ +.term-bg42 { background: #99ff5f; } /* green */ + +/* custom foreground/background combos for readability */ +.term-fg31.term-bg40 { color: #F8A39F; } + +/* xterm colors */ +.term-fgx16 { color: #000000; } +.term-fgx17 { color: #00005f; } +.term-fgx18 { color: #000087; } +.term-fgx19 { color: #0000af; } +.term-fgx20 { color: #0000d7; } +.term-fgx21 { color: #0000ff; } +.term-fgx22 { color: #005f00; } +.term-fgx23 { color: #005f5f; } +.term-fgx24 { color: #005f87; } +.term-fgx25 { color: #005faf; } +.term-fgx26 { color: #005fd7; } +.term-fgx27 { color: #005fff; } +.term-fgx28 { color: #008700; } +.term-fgx29 { color: #00875f; } +.term-fgx30 { color: #008787; } +.term-fgx31 { color: #0087af; } +.term-fgx32 { color: #0087d7; } +.term-fgx33 { color: #0087ff; } +.term-fgx34 { color: #00af00; } +.term-fgx35 { color: #00af5f; } +.term-fgx36 { color: #00af87; } +.term-fgx37 { color: #00afaf; } +.term-fgx38 { color: #00afd7; } +.term-fgx39 { color: #00afff; } +.term-fgx40 { color: #00d700; } +.term-fgx41 { color: #00d75f; } +.term-fgx42 { color: #00d787; } +.term-fgx43 { color: #00d7af; } +.term-fgx44 { color: #00d7d7; } +.term-fgx45 { color: #00d7ff; } +.term-fgx46 { color: #00ff00; } +.term-fgx47 { color: #00ff5f; } +.term-fgx48 { color: #00ff87; } +.term-fgx49 { color: #00ffaf; } +.term-fgx50 { color: #00ffd7; } +.term-fgx51 { color: #00ffff; } +.term-fgx52 { color: #5f0000; } +.term-fgx53 { color: #5f005f; } +.term-fgx54 { color: #5f0087; } +.term-fgx55 { color: #5f00af; } +.term-fgx56 { color: #5f00d7; } +.term-fgx57 { color: #5f00ff; } +.term-fgx58 { color: #5f5f00; } +.term-fgx59 { color: #5f5f5f; } +.term-fgx60 { color: #5f5f87; } +.term-fgx61 { color: #5f5faf; } +.term-fgx62 { color: #5f5fd7; } +.term-fgx63 { color: #5f5fff; } +.term-fgx64 { color: #5f8700; } +.term-fgx65 { color: #5f875f; } +.term-fgx66 { color: #5f8787; } +.term-fgx67 { color: #5f87af; } +.term-fgx68 { color: #5f87d7; } +.term-fgx69 { color: #5f87ff; } +.term-fgx70 { color: #5faf00; } +.term-fgx71 { color: #5faf5f; } +.term-fgx72 { color: #5faf87; } +.term-fgx73 { color: #5fafaf; } +.term-fgx74 { color: #5fafd7; } +.term-fgx75 { color: #5fafff; } +.term-fgx76 { color: #5fd700; } +.term-fgx77 { color: #5fd75f; } +.term-fgx78 { color: #5fd787; } +.term-fgx79 { color: #5fd7af; } +.term-fgx80 { color: #5fd7d7; } +.term-fgx81 { color: #5fd7ff; } +.term-fgx82 { color: #5fff00; } +.term-fgx83 { color: #5fff5f; } +.term-fgx84 { color: #5fff87; } +.term-fgx85 { color: #5fffaf; } +.term-fgx86 { color: #5fffd7; } +.term-fgx87 { color: #5fffff; } +.term-fgx88 { color: #870000; } +.term-fgx89 { color: #87005f; } +.term-fgx90 { color: #870087; } +.term-fgx91 { color: #8700af; } +.term-fgx92 { color: #8700d7; } +.term-fgx93 { color: #8700ff; } +.term-fgx94 { color: #875f00; } +.term-fgx95 { color: #875f5f; } +.term-fgx96 { color: #875f87; } +.term-fgx97 { color: #875faf; } +.term-fgx98 { color: #875fd7; } +.term-fgx99 { color: #875fff; } +.term-fgx100 { color: #878700; } +.term-fgx101 { color: #87875f; } +.term-fgx102 { color: #878787; } +.term-fgx103 { color: #8787af; } +.term-fgx104 { color: #8787d7; } +.term-fgx105 { color: #8787ff; } +.term-fgx106 { color: #87af00; } +.term-fgx107 { color: #87af5f; } +.term-fgx108 { color: #87af87; } +.term-fgx109 { color: #87afaf; } +.term-fgx110 { color: #87afd7; } +.term-fgx111 { color: #87afff; } +.term-fgx112 { color: #87d700; } +.term-fgx113 { color: #87d75f; } +.term-fgx114 { color: #87d787; } +.term-fgx115 { color: #87d7af; } +.term-fgx116 { color: #87d7d7; } +.term-fgx117 { color: #87d7ff; } +.term-fgx118 { color: #87ff00; } +.term-fgx119 { color: #87ff5f; } +.term-fgx120 { color: #87ff87; } +.term-fgx121 { color: #87ffaf; } +.term-fgx122 { color: #87ffd7; } +.term-fgx123 { color: #87ffff; } +.term-fgx124 { color: #af0000; } +.term-fgx125 { color: #af005f; } +.term-fgx126 { color: #af0087; } +.term-fgx127 { color: #af00af; } +.term-fgx128 { color: #af00d7; } +.term-fgx129 { color: #af00ff; } +.term-fgx130 { color: #af5f00; } +.term-fgx131 { color: #af5f5f; } +.term-fgx132 { color: #af5f87; } +.term-fgx133 { color: #af5faf; } +.term-fgx134 { color: #af5fd7; } +.term-fgx135 { color: #af5fff; } +.term-fgx136 { color: #af8700; } +.term-fgx137 { color: #af875f; } +.term-fgx138 { color: #af8787; } +.term-fgx139 { color: #af87af; } +.term-fgx140 { color: #af87d7; } +.term-fgx141 { color: #af87ff; } +.term-fgx142 { color: #afaf00; } +.term-fgx143 { color: #afaf5f; } +.term-fgx144 { color: #afaf87; } +.term-fgx145 { color: #afafaf; } +.term-fgx146 { color: #afafd7; } +.term-fgx147 { color: #afafff; } +.term-fgx148 { color: #afd700; } +.term-fgx149 { color: #afd75f; } +.term-fgx150 { color: #afd787; } +.term-fgx151 { color: #afd7af; } +.term-fgx152 { color: #afd7d7; } +.term-fgx153 { color: #afd7ff; } +.term-fgx154 { color: #afff00; } +.term-fgx155 { color: #afff5f; } +.term-fgx156 { color: #afff87; } +.term-fgx157 { color: #afffaf; } +.term-fgx158 { color: #afffd7; } +.term-fgx159 { color: #afffff; } +.term-fgx160 { color: #d70000; } +.term-fgx161 { color: #d7005f; } +.term-fgx162 { color: #d70087; } +.term-fgx163 { color: #d700af; } +.term-fgx164 { color: #d700d7; } +.term-fgx165 { color: #d700ff; } +.term-fgx166 { color: #d75f00; } +.term-fgx167 { color: #d75f5f; } +.term-fgx168 { color: #d75f87; } +.term-fgx169 { color: #d75faf; } +.term-fgx170 { color: #d75fd7; } +.term-fgx171 { color: #d75fff; } +.term-fgx172 { color: #d78700; } +.term-fgx173 { color: #d7875f; } +.term-fgx174 { color: #d78787; } +.term-fgx175 { color: #d787af; } +.term-fgx176 { color: #d787d7; } +.term-fgx177 { color: #d787ff; } +.term-fgx178 { color: #d7af00; } +.term-fgx179 { color: #d7af5f; } +.term-fgx180 { color: #d7af87; } +.term-fgx181 { color: #d7afaf; } +.term-fgx182 { color: #d7afd7; } +.term-fgx183 { color: #d7afff; } +.term-fgx184 { color: #d7d700; } +.term-fgx185 { color: #d7d75f; } +.term-fgx186 { color: #d7d787; } +.term-fgx187 { color: #d7d7af; } +.term-fgx188 { color: #d7d7d7; } +.term-fgx189 { color: #d7d7ff; } +.term-fgx190 { color: #d7ff00; } +.term-fgx191 { color: #d7ff5f; } +.term-fgx192 { color: #d7ff87; } +.term-fgx193 { color: #d7ffaf; } +.term-fgx194 { color: #d7ffd7; } +.term-fgx195 { color: #d7ffff; } +.term-fgx196 { color: #ff0000; } +.term-fgx197 { color: #ff005f; } +.term-fgx198 { color: #ff0087; } +.term-fgx199 { color: #ff00af; } +.term-fgx200 { color: #ff00d7; } +.term-fgx201 { color: #ff00ff; } +.term-fgx202 { color: #ff5f00; } +.term-fgx203 { color: #ff5f5f; } +.term-fgx204 { color: #ff5f87; } +.term-fgx205 { color: #ff5faf; } +.term-fgx206 { color: #ff5fd7; } +.term-fgx207 { color: #ff5fff; } +.term-fgx208 { color: #ff8700; } +.term-fgx209 { color: #ff875f; } +.term-fgx210 { color: #ff8787; } +.term-fgx211 { color: #ff87af; } +.term-fgx212 { color: #ff87d7; } +.term-fgx213 { color: #ff87ff; } +.term-fgx214 { color: #ffaf00; } +.term-fgx215 { color: #ffaf5f; } +.term-fgx216 { color: #ffaf87; } +.term-fgx217 { color: #ffafaf; } +.term-fgx218 { color: #ffafd7; } +.term-fgx219 { color: #ffafff; } +.term-fgx220 { color: #ffd700; } +.term-fgx221 { color: #ffd75f; } +.term-fgx222 { color: #ffd787; } +.term-fgx223 { color: #ffd7af; } +.term-fgx224 { color: #ffd7d7; } +.term-fgx225 { color: #ffd7ff; } +.term-fgx226 { color: #ffff00; } +.term-fgx227 { color: #ffff5f; } +.term-fgx228 { color: #ffff87; } +.term-fgx229 { color: #ffffaf; } +.term-fgx230 { color: #ffffd7; } +.term-fgx231 { color: #ffffff; } +.term-fgx232 { color: #080808; } +.term-fgx233 { color: #121212; } +.term-fgx234 { color: #1c1c1c; } +.term-fgx235 { color: #262626; } +.term-fgx236 { color: #303030; } +.term-fgx237 { color: #3a3a3a; } +.term-fgx238 { color: #444444; } +.term-fgx239 { color: #4e4e4e; } +.term-fgx240 { color: #585858; } +.term-fgx241 { color: #626262; } +.term-fgx242 { color: #6c6c6c; } +.term-fgx243 { color: #767676; } +.term-fgx244 { color: #808080; } +.term-fgx245 { color: #8a8a8a; } +.term-fgx246 { color: #949494; } +.term-fgx247 { color: #9e9e9e; } +.term-fgx248 { color: #a8a8a8; } +.term-fgx249 { color: #b2b2b2; } +.term-fgx250 { color: #bcbcbc; } +.term-fgx251 { color: #c6c6c6; } +.term-fgx252 { color: #d0d0d0; } +.term-fgx253 { color: #dadada; } +.term-fgx254 { color: #e4e4e4; } +.term-fgx255 { color: #eeeeee; } diff --git a/src/dependencies.qmd b/src/dependencies.qmd index 48950a5..b34a0f0 100644 --- a/src/dependencies.qmd +++ b/src/dependencies.qmd @@ -44,7 +44,7 @@ - Ideally automate the fetching of the data ::: :::{.column width="40%"} -![Example of a zenodo listing. Note how each version of the dataset has a different reference](img/zenodo.png) +![Example of a zenodo listing. Note how each version of the dataset has a different reference](images/zenodo.png) ::: ::: @@ -91,9 +91,9 @@ - Portable and cross-platform ::: :::{.column width="40%"} -![](img/docker-logo-ocean-blue.svg) -![](img/apptainer.svg) -![](img/podman-logo-source.svg) +![](images/docker-logo-ocean-blue.svg) +![](images/apptainer.svg) +![](images/podman-logo-source.svg) ::: ::: @@ -101,9 +101,6 @@ \ -:::{.columns} -:::{.column width="60%"} - - Declarative package managers - Use pure functional languages to create environments - same inputs = same outputs @@ -112,14 +109,5 @@ - can lookup if package already exists locally - Publicly hosted and *versioned* package repository - All packages have defined and unchanging dependencies -- Handles all dependencies automatically +- Handle all dependencies automatically - even linked libraries, so no hidden dependencies! -::: -:::{.column width="40%"} -How they differ: - -- Nix language vs Guile scheme -- Guix package repository only hosts fully open source packages - - Can be difficult when using vendor-locked software e.g. CUDA -::: -::: diff --git a/src/documentation.qmd b/src/documentation.qmd index 9481a5e..04565d2 100644 --- a/src/documentation.qmd +++ b/src/documentation.qmd @@ -23,10 +23,19 @@ :::: ::::{.column width=50%} -![](img/ftorch-readme.png) +![](images/ftorch-readme.png) :::: ::: +## Licences + +- Licences are necessary for reproducibility! +- They define how code can be used/reused +- Enforce openness of code and data + - FOSS licenses eg. GPL, MIT, BSD, etc +- Many explanations of which licence to use exist (and I'm not a lawyer!) + - [choosealicense.com](https://choosealicense.com/) + ## Comments - Comments in code are also another form of documentation @@ -34,18 +43,44 @@ - Explain *why* the code is doing something - Give context that is external to the scope +## Docstrings + +:::{.columns} + +::::{.column width=50%} +- Docstrings are a description embedded in the definition of something + - e.g. functions, classes +- Describe how to *use* something, rather than how it works +- Often standardised in a language + - e.g. for Python [PEP257](https://peps.python.org/pep-0257/) +- There are various conventions for how to write/format them e.g. [numpy](https://numpydoc.readthedocs.io/en/latest/format.html) +:::: +::::{.column width=50%} +```{.python} +def energy_balanced_temperature(emissivity, albedo): + """ + The temperature of Earth assuming 0D energy balance model + + Parameters + ---------- + emissivity: float + Effective emmissivity of the Earth + albedo: float + Effective albedo of the Earth + + Returns + ------- + temperature: float + Temperature of Earth's surface assuming 0D energy balance model [K] + """ + return (SOLAR_CONSTANT * (1.0 - albedo) / (4.0 * emissivity * SIGMA))**0.25 +``` +:::: +::: + ## Generating Docs - Use tools that generate docs from source code - Single source of truth - Comments/Docstrings embedded in code - Reduce separation between code and docs - -## Licences - -- Licences are necessary for reproducibility! -- They define how code can be used/reused -- Enforce openness of code and data - - FOSS licenses eg. GPL, MIT, BSD, etc -- Many explanations of which licence to use exist (and I'm not a lawyer!) -- [choosealicense.com](https://choosealicense.com/) diff --git a/src/fair_principles.qmd b/src/fair_principles.qmd index 2f34601..8fb82d3 100644 --- a/src/fair_principles.qmd +++ b/src/fair_principles.qmd @@ -8,7 +8,7 @@ The FAIR principles were first introduced for data, and later adapted for resear FAIR stands for -![](img/FAIR_data_principles.png){width=80%} +![](images/FAIR_data_principles.png){width=80%} [^1]: diff --git a/src/img/FAIR_data_principles.png b/src/images/FAIR_data_principles.png similarity index 100% rename from src/img/FAIR_data_principles.png rename to src/images/FAIR_data_principles.png diff --git a/src/img/Guix.png b/src/images/Guix.png similarity index 100% rename from src/img/Guix.png rename to src/images/Guix.png diff --git a/src/img/RIOT_principles.png b/src/images/RIOT_principles.png similarity index 100% rename from src/img/RIOT_principles.png rename to src/images/RIOT_principles.png diff --git a/src/img/acm.png b/src/images/acm.png similarity index 100% rename from src/img/acm.png rename to src/images/acm.png diff --git a/src/img/acm_badges.jpg b/src/images/acm_badges.jpg similarity index 100% rename from src/img/acm_badges.jpg rename to src/images/acm_badges.jpg diff --git a/src/img/apptainer.svg b/src/images/apptainer.svg similarity index 100% rename from src/img/apptainer.svg rename to src/images/apptainer.svg diff --git a/src/img/cat-flower.jpeg b/src/images/cat-flower.jpeg similarity index 100% rename from src/img/cat-flower.jpeg rename to src/images/cat-flower.jpeg diff --git a/src/img/docker-logo-ocean-blue.svg b/src/images/docker-logo-ocean-blue.svg similarity index 100% rename from src/img/docker-logo-ocean-blue.svg rename to src/images/docker-logo-ocean-blue.svg diff --git a/src/img/es_reproducibility_perception.jpg b/src/images/es_reproducibility_perception.jpg similarity index 100% rename from src/img/es_reproducibility_perception.jpg rename to src/images/es_reproducibility_perception.jpg diff --git a/src/img/es_reproducibility_reasons.jpg b/src/images/es_reproducibility_reasons.jpg similarity index 100% rename from src/img/es_reproducibility_reasons.jpg rename to src/images/es_reproducibility_reasons.jpg diff --git a/src/img/es_reproducibility_reasons_only.jpg b/src/images/es_reproducibility_reasons_only.jpg similarity index 100% rename from src/img/es_reproducibility_reasons_only.jpg rename to src/images/es_reproducibility_reasons_only.jpg diff --git a/src/img/es_reproducibility_solutions.jpg b/src/images/es_reproducibility_solutions.jpg similarity index 100% rename from src/img/es_reproducibility_solutions.jpg rename to src/images/es_reproducibility_solutions.jpg diff --git a/src/img/fear.jpeg b/src/images/fear.jpeg similarity index 100% rename from src/img/fear.jpeg rename to src/images/fear.jpeg diff --git a/src/img/ftorch-readme.png b/src/images/ftorch-readme.png similarity index 100% rename from src/img/ftorch-readme.png rename to src/images/ftorch-readme.png diff --git a/src/images/git.png b/src/images/git.png new file mode 120000 index 0000000..64bd8c6 --- /dev/null +++ b/src/images/git.png @@ -0,0 +1 @@ +../Summer-school-Intro-Git/slides/images/git.png \ No newline at end of file diff --git a/src/images/github-mark.svg b/src/images/github-mark.svg new file mode 120000 index 0000000..446c27f --- /dev/null +++ b/src/images/github-mark.svg @@ -0,0 +1 @@ +../Summer-school-Intro-Git/slides/images/github-mark.svg \ No newline at end of file diff --git a/src/images/iccs-ss-qr.svg b/src/images/iccs-ss-qr.svg new file mode 100644 index 0000000..4dc07e2 --- /dev/null +++ b/src/images/iccs-ss-qr.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/images/iccs-summer-school-2026.jpg b/src/images/iccs-summer-school-2026.jpg new file mode 100644 index 0000000..cfaaf7a Binary files /dev/null and b/src/images/iccs-summer-school-2026.jpg differ diff --git a/src/img/iccs_hacktoberfest_2026.png b/src/images/iccs_hacktoberfest_2026.png similarity index 100% rename from src/img/iccs_hacktoberfest_2026.png rename to src/images/iccs_hacktoberfest_2026.png diff --git a/src/img/nixos-logo.svg b/src/images/nixos-logo.svg similarity index 100% rename from src/img/nixos-logo.svg rename to src/images/nixos-logo.svg diff --git a/src/img/podman-logo-source.svg b/src/images/podman-logo-source.svg similarity index 100% rename from src/img/podman-logo-source.svg rename to src/images/podman-logo-source.svg diff --git a/src/images/pytest.png b/src/images/pytest.png new file mode 100644 index 0000000..35162f0 Binary files /dev/null and b/src/images/pytest.png differ diff --git a/src/img/reproducibility_matrix.jpg b/src/images/reproducibility_matrix.jpg similarity index 100% rename from src/img/reproducibility_matrix.jpg rename to src/images/reproducibility_matrix.jpg diff --git a/src/img/reprohack-hub.png b/src/images/reprohack-hub.png similarity index 100% rename from src/img/reprohack-hub.png rename to src/images/reprohack-hub.png diff --git a/src/img/reprohack_logo.jpg b/src/images/reprohack_logo.jpg similarity index 100% rename from src/img/reprohack_logo.jpg rename to src/images/reprohack_logo.jpg diff --git a/src/img/riots.png b/src/images/riots.png similarity index 100% rename from src/img/riots.png rename to src/images/riots.png diff --git a/src/img/sc26.png b/src/images/sc26.png similarity index 100% rename from src/img/sc26.png rename to src/images/sc26.png diff --git a/src/img/scientists_nightmare.png b/src/images/scientists_nightmare.png similarity index 100% rename from src/img/scientists_nightmare.png rename to src/images/scientists_nightmare.png diff --git a/src/images/show_different_file_states.png b/src/images/show_different_file_states.png new file mode 120000 index 0000000..087fdd9 --- /dev/null +++ b/src/images/show_different_file_states.png @@ -0,0 +1 @@ +../Summer-school-Intro-Git/slides/images/show_different_file_states.png \ No newline at end of file diff --git a/src/img/theturingway-pathway.png b/src/images/theturingway-pathway.png similarity index 100% rename from src/img/theturingway-pathway.png rename to src/images/theturingway-pathway.png diff --git a/src/img/turingway.png b/src/images/turingway.png similarity index 100% rename from src/img/turingway.png rename to src/images/turingway.png diff --git a/src/img/ukrn.png b/src/images/ukrn.png similarity index 100% rename from src/img/ukrn.png rename to src/images/ukrn.png diff --git a/src/img/ukrnlogo.jpeg b/src/images/ukrnlogo.jpeg similarity index 100% rename from src/img/ukrnlogo.jpeg rename to src/images/ukrnlogo.jpeg diff --git a/src/img/zenodo.png b/src/images/zenodo.png similarity index 100% rename from src/img/zenodo.png rename to src/images/zenodo.png diff --git a/src/introduction.qmd b/src/introduction.qmd index 51f76ed..883831b 100644 --- a/src/introduction.qmd +++ b/src/introduction.qmd @@ -4,7 +4,7 @@ In scientific research, a result is: -![](/img/reproducibility_matrix.jpg){width=60%, fig-align="center"} +![](/images/reproducibility_matrix.jpg){width=60%, fig-align="center"} :::{.footer} We will use the definitions used in [The Turing Way](https://book.the-turing-way.org/reproducible-research/overview/overview-definitions/) @@ -161,12 +161,12 @@ Other findings: - By making our software more reproducible, we also get to reap the benefits! :::{.columns} -:::{.column .fragment width="50%"} +:::{.column .fragment .left-column width="50%"} ### Safely implement changes - Automation and testing help catch mistakes before they become an issue ::: -:::{.column .fragment width=50%} +:::{.column .fragment .right-column width=50%} ### Rerun analyses - Create reusable pipelines @@ -175,13 +175,13 @@ Other findings: ::: :::{.columns} -:::{.column .fragment width=50%} +:::{.column .fragment .left-column width=50%} ### Faster onboarding - Better documentation on how to use the software - Relevant metadata present - no hunting down dependencies ::: -:::{.column .fragment width=50%} +:::{.column .fragment .right-column width=50%} ### Better collaboration - Version control for keeping track of code history diff --git a/src/reproducibility_initiatives.qmd b/src/reproducibility_initiatives.qmd index 14cf6b7..fa5a68e 100644 --- a/src/reproducibility_initiatives.qmd +++ b/src/reproducibility_initiatives.qmd @@ -16,7 +16,7 @@ thing (internationally). --- -## ![](img/ukrnlogo.jpeg){style="width:1.5cm; vertical-align:bottom;"} UK Reproducibility Network +## ![](images/ukrnlogo.jpeg){style="width:1.5cm; vertical-align:bottom;"} UK Reproducibility Network - Peer-led consortium within the UK, international networks @@ -26,12 +26,12 @@ thing (internationally). - -![](img/ukrn.png){width=80%, fig-align="center"} +![](images/ukrn.png){width=80%, fig-align="center"} --- -## ![](img/riots.png){style="width: 5%"} RIOT Science +## ![](images/riots.png){style="width: 5%"} RIOT Science :::: {.columns} @@ -43,7 +43,7 @@ thing (internationally). ::: ::: {.column style="width: 50%; fig-align: center; "} -![](img/RIOT_principles.png){style="width: 80%; background-color: white;"} +![](images/RIOT_principles.png){style="width: 80%; background-color: white;"} ::: :::: @@ -62,12 +62,12 @@ thing (internationally). - Collaboration ::: :::{.column width=70%} -![](img/theturingway-pathway.png){width=80%, fig-align="center"} +![](images/theturingway-pathway.png){width=80%, fig-align="center"} ::: ::: --- -## ![](img/acm.png){style="width:20%; vertical-align:text-bottom;"} ACM Reproducibility Badges +## ![](images/acm.png){style="width:20%; vertical-align:text-bottom;"} ACM Reproducibility Badges   @@ -80,14 +80,14 @@ thing (internationally). ::: ::: {.column width="50%"} -![](img/acm_badges.jpg){style="width:90%; fig-align:center"} +![](images/acm_badges.jpg){style="width:90%; fig-align:center"} ::: :::: --- -## ![](img/sc26.png){width=10%} SC Reproducibility Initiative +## ![](images/sc26.png){width=10%} SC Reproducibility Initiative   @@ -108,7 +108,7 @@ Performance Computing Networking, Storage, and Analysis --- -## ![](img/reprohack_logo.jpg){width=5%} ReproHack +## ![](images/reprohack_logo.jpg){width=5%} ReproHack - __Challenge__: Reproduce the results of a paper in one day! @@ -129,7 +129,7 @@ course by Owen Petchey) - Events listing - Support through ReproHack Slack -![](img/reprohack-hub.png) +![](images/reprohack-hub.png) --- diff --git a/src/slides.qmd b/src/slides.qmd index adf3e88..0e90e49 100644 --- a/src/slides.qmd +++ b/src/slides.qmd @@ -6,10 +6,27 @@ format: revealjs: theme: [dracula, custom.scss] logo: https://iccs.cam.ac.uk/sites/default/files/iccs_ucam_combined_reverse_colour.png + embed-resources: false + + smaller: true + slide-number: false + incremental: false + history: false + chalkboard: false + preview-links: auto + + highlight-style: github + code-overflow: scroll + code-line-numbers: false + +revealjs-plugins: + - attribution authors: - name: Jack Franklin + affiliations: ICCS - University of Cambridge - name: Marion Weinzierl + affiliations: ICCS - University of Cambridge jupyter: python3 @@ -29,6 +46,8 @@ execute: {{< include ../exercises/automation_exercises.qmd >}} {{< include testing.qmd >}} +{{< include _pytest.qmd >}} +{{< include ../exercises/testing_exercises.qmd >}} {{< include documentation.qmd >}} {{< include ../exercises/documentation_exercises.qmd >}} @@ -78,6 +97,16 @@ Additional benefits: - Follow best practice for new code - Implement small improvements whenever modifying -## ICCS Hacktoberfest 2026 +## ICCS Summer School 2027 + +### Confirmed for 28/06 - 02/07! -![](img/iccs_hacktoberfest_2026){width=80%, fig-align="center"} +:::{.columns} +::::{.column width=30%} +Register your interest here: +![](images/iccs-ss-qr.svg) +:::: +::::{.column width=70%} +![](images/iccs-summer-school-2026.jpg) +:::: +::: diff --git a/src/testing.qmd b/src/testing.qmd index 0221e71..d3f1c43 100644 --- a/src/testing.qmd +++ b/src/testing.qmd @@ -24,6 +24,9 @@ ## A very short intro to testing +:::{.columns} +::::{.column width=50%} + ### Unit tests - Test the smallest logical unit of the code @@ -31,6 +34,9 @@ - Test functions for known results - Compare to previously produced results +:::: +::::{.column width=50%} + ### Integration tests - Test that components work together @@ -38,6 +44,9 @@ - Can use previous results to validate model - Ensure no regression of results +:::: +::: + --- ## Adding tests to a project diff --git a/src/version_control.qmd b/src/version_control.qmd index 3904194..116297c 100644 --- a/src/version_control.qmd +++ b/src/version_control.qmd @@ -1,21 +1,18 @@ # Version Control -## Version Control +{{< include Summer-school-Intro-Git/slides/_version_control.qmd >}} -\ +{{< include Summer-school-Intro-Git/slides/_basics.qmd >}} -- The first thing we should do is move our project into version control (VC) -- This way we never lose the original state of the project -- We can then try things without worrying about breaking anything! -- This will also benefit any later development, so the sooner the better +{{< include Summer-school-Intro-Git/slides/_branching.qmd >}} -## What to add to VC +# Version Control in practice -\ +## What to add to VC - DON'T do this: - ```console - git add . + ``` bash + $ git add . ``` - Our repository should only contain: @@ -37,14 +34,50 @@ it will be true. - Use `.gitignore` to automatically ignore any unwanted files - e.g. build outputs -## Aside - testing with worktrees + +## Atomic commits + +- Commits should relate to specific logical changes + - Makes it easier to understand what changed + - Can undo changes + - Easier to locate breaking changes (see `git bisect`) + +## Atomic commits \ +### Bad +``` bash +$ git log --all --decorate --oneline --graph + * 25b29af Add branches content + * 9df21b6 Move figures +``` + +\ + +### Still bad! +``` bash +$ git log --all --decorate --oneline --graph + * 25b29af Add branches content and add submodules to GH actions + * 9df21b6 Move figures into `images` directory +``` + +\ + +### Better! +``` bash +$ git log --all --decorate --oneline --graph + * 25b29af Add branches content + * 16b1a94 Add submodules to GH actions + * 9df21b6 Move all figures into `images` directory +``` + +# Aside - testing with worktrees + - git worktrees are like "local clones" of a repository - Create a worktree: ``` bash -git worktree add -b +$ git worktree add -b ``` - Will make a new directory, with only files that are tracked - Can use as a cleanroom to ensure all dependencies are there