From 11f8bf6db26931a55dce5e7edac97fe7cd3b4afd Mon Sep 17 00:00:00 2001 From: katamartin Date: Mon, 24 Jun 2024 17:15:28 -0400 Subject: [PATCH 01/11] Add OAE efficiency to tools list --- components/tool-logos/index.js | 1 + components/tool-logos/oae-efficiency.js | 271 ++++++++++++++++++++++++ contents/tools.js | 8 + 3 files changed, 280 insertions(+) create mode 100644 components/tool-logos/oae-efficiency.js diff --git a/components/tool-logos/index.js b/components/tool-logos/index.js index 976937ce..96590d31 100644 --- a/components/tool-logos/index.js +++ b/components/tool-logos/index.js @@ -12,3 +12,4 @@ export { default as CMIP6Downscaling } from './cmip6-downscaling' export { default as CDRVerification } from './cdr-verification' export { default as EWQuantification } from './ew-quantification' export { default as OffsetsDB } from './offsets-db' +export { default as OAEEfficiency } from './oae-efficiency' diff --git a/components/tool-logos/oae-efficiency.js b/components/tool-logos/oae-efficiency.js new file mode 100644 index 00000000..af1db1af --- /dev/null +++ b/components/tool-logos/oae-efficiency.js @@ -0,0 +1,271 @@ +import { useThemeUI } from 'theme-ui' + +const Logo = () => { + const { theme } = useThemeUI() + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default Logo diff --git a/contents/tools.js b/contents/tools.js index f1dc84e4..ac78ff4a 100644 --- a/contents/tools.js +++ b/contents/tools.js @@ -13,9 +13,17 @@ import { CDRVerification, EWQuantification, OffsetsDB, + OAEEfficiency, } from '../components/tool-logos' const tools = [ + { + id: 'oae-efficiency', + logo: , + color: 'blue', + summary: 'Mapping the efficiency of ocean alkalinity enhancement.', + title: 'OAE Efficiency', + }, { id: 'offsets-db', logo: , From 2d8d578f439376ec423033bff5af1fc0893e97eb Mon Sep 17 00:00:00 2001 From: katamartin Date: Mon, 24 Jun 2024 17:21:18 -0400 Subject: [PATCH 02/11] Tweak opacity --- components/tool-logos/oae-efficiency.js | 76 ++++++++++++++----------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/components/tool-logos/oae-efficiency.js b/components/tool-logos/oae-efficiency.js index af1db1af..d9d21787 100644 --- a/components/tool-logos/oae-efficiency.js +++ b/components/tool-logos/oae-efficiency.js @@ -16,252 +16,264 @@ const Logo = () => { d='M65.2354 -28.8945H69.4316V-25.5456H73.6143V-22.1564H77.8105V-18.7268H82.0067V-11.7063H77.8105V2.87279H65.2354V6.62515H61.0392V-0.839227H56.843V-4.51089H52.6603V-11.7063H48.4641V-15.2434H52.6603V-18.7268H56.843V-22.1564H61.0392V-25.5456H65.2354V-28.8945Z' fill={theme.colors.blue} stroke={theme.colors.background} + fillOpacity='0.9' /> From 6a2b7d4aaa2c5b6365a22c9b1d39c1a54edb1e2c Mon Sep 17 00:00:00 2001 From: katamartin Date: Tue, 25 Jun 2024 12:46:35 -0400 Subject: [PATCH 03/11] Add highlight --- components/highlights.js | 47 ++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/components/highlights.js b/components/highlights.js index 6d9ee0ee..3b0e12e8 100644 --- a/components/highlights.js +++ b/components/highlights.js @@ -4,43 +4,48 @@ import Highlight from './highlight' const HIGHLIGHTS = [ { - id: 'offsets-db', - date: '03-08-2024', - href: '/research/offsets-db', - title: 'OffsetsDB', + id: 'oae-efficiency', + date: '06-27-2024', + href: '/research/oae-efficiency-explainer', + title: 'Mapping the efficiency of ocean alkalinity enhancement', summary: - 'We developed a regularly-updating, harmonized database of carbon offset projects and credits for download and interactive exploration.', + 'We developed a tool to explore a new dataset that makes it easier to see how the efficiency of ocean alkalinity enhancement varies around the world, in collaboration with [C]Worthy.', links: [ - { label: 'Database tool', href: '/research/offsets-db' }, + { + label: 'Map tool', + href: '/research/oae-efficiency', + }, { label: 'Explainer article', - href: '/research/offsets-db-explainer', + href: '/research/oae-efficiency-explainer', }, { - label: 'Methods', - href: '/research/offsets-db-methods', + label: 'Preprint', + href: 'https://www.researchsquare.com/article/rs-4124909/v1', + }, + { + label: 'Dataset', + href: 'https://beta.source.coop/repositories/cworthy/oae-efficiency-atlas/description/', }, ], }, + { - id: 'extreme-heat', - date: '09-05-2023', - href: '/research/extreme-heat-explainer', - title: 'Modeling extreme heat', + id: 'offsets-db', + date: '03-08-2024', + href: '/research/offsets-db', + title: 'OffsetsDB', summary: - 'We developed a new dataset modeling the impacts of humid heat now and into the future, in collaboration with The Washington Post. Read the article or the coverage in The Post.', + 'We developed a regularly-updating, harmonized database of carbon offset projects and credits for download and interactive exploration.', links: [ + { label: 'Database tool', href: '/research/offsets-db' }, { label: 'Explainer article', - href: '/research/extreme-heat-explainer', - }, - { - label: 'Press coverage #1', - href: 'https://www.washingtonpost.com/climate-environment/interactive/2023/extreme-heat-wet-bulb-globe-temperature/', + href: '/research/offsets-db-explainer', }, { - label: 'Press coverage #2', - href: 'https://www.washingtonpost.com/climate-environment/interactive/2023/pakistan-extreme-heat-health-impacts-death/', + label: 'Methods', + href: '/research/offsets-db-methods', }, ], }, From 933202026ca7cc85f259374f4e501eb91d95cac1 Mon Sep 17 00:00:00 2001 From: katamartin Date: Tue, 25 Jun 2024 13:11:13 -0400 Subject: [PATCH 04/11] Tweak tool logo colors --- components/tool-logos/oae-efficiency.js | 143 +++++++++--------------- 1 file changed, 51 insertions(+), 92 deletions(-) diff --git a/components/tool-logos/oae-efficiency.js b/components/tool-logos/oae-efficiency.js index d9d21787..68bad6c8 100644 --- a/components/tool-logos/oae-efficiency.js +++ b/components/tool-logos/oae-efficiency.js @@ -1,7 +1,15 @@ import { useThemeUI } from 'theme-ui' +import { useThemedColormap } from '@carbonplan/colormaps' + +const getColor = (colormap, ratio) => { + const rgb = colormap[Math.round(colormap.length * (ratio + 0.1))] + + return `rgb(${rgb[0]}, ${rgb[1]}, ${rgb[2]})` +} const Logo = () => { const { theme } = useThemeUI() + const colormap = useThemedColormap('cool') return ( { > - From 982203a81c51cbafef0f8106797c14ef582cc6ed Mon Sep 17 00:00:00 2001 From: katamartin Date: Tue, 2 Jul 2024 15:55:49 -0400 Subject: [PATCH 05/11] Tweak color --- contents/tools.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contents/tools.js b/contents/tools.js index ac78ff4a..f8761baf 100644 --- a/contents/tools.js +++ b/contents/tools.js @@ -20,7 +20,7 @@ const tools = [ { id: 'oae-efficiency', logo: , - color: 'blue', + color: 'secondary', summary: 'Mapping the efficiency of ocean alkalinity enhancement.', title: 'OAE Efficiency', }, From 8ba967c3fab8f58a8b7566bf65eca1826134555e Mon Sep 17 00:00:00 2001 From: katamartin Date: Mon, 15 Jul 2024 13:24:53 -0400 Subject: [PATCH 06/11] Add dependency --- package-lock.json | 31 +++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 32 insertions(+) diff --git a/package-lock.json b/package-lock.json index 03d0fce7..4caf4469 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,6 +40,7 @@ "d3-shape": "^3.0.1", "gray-matter": "^4.0.3", "mapbox-gl": "^1.13.1", + "ndarray-concat-cols": "^1.0.0", "next": "^12.0.5", "next-mdx-remote": "^4.1.0", "react": "^18.2.0", @@ -7926,6 +7927,16 @@ "is-buffer": "^1.0.2" } }, + "node_modules/ndarray-concat-cols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ndarray-concat-cols/-/ndarray-concat-cols-1.0.0.tgz", + "integrity": "sha512-3U1K5p8rNUCyj34CCsSlVXVb5ZT+nac74EfeIiiyjixXnwQCugzpgTdQBFZ+hZz+vcOPPYH7nQhh1Bpij/Cb1A==", + "dependencies": { + "ndarray-ops": "^1.2.2", + "ndarray-scratch": "^1.2.0", + "util-extend": "^1.0.1" + } + }, "node_modules/ndarray-ops": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ndarray-ops/-/ndarray-ops-1.2.2.tgz", @@ -9788,6 +9799,11 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "node_modules/util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==" + }, "node_modules/uvu": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", @@ -16145,6 +16161,16 @@ } } }, + "ndarray-concat-cols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ndarray-concat-cols/-/ndarray-concat-cols-1.0.0.tgz", + "integrity": "sha512-3U1K5p8rNUCyj34CCsSlVXVb5ZT+nac74EfeIiiyjixXnwQCugzpgTdQBFZ+hZz+vcOPPYH7nQhh1Bpij/Cb1A==", + "requires": { + "ndarray-ops": "^1.2.2", + "ndarray-scratch": "^1.2.0", + "util-extend": "^1.0.1" + } + }, "ndarray-ops": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ndarray-ops/-/ndarray-ops-1.2.2.tgz", @@ -17499,6 +17525,11 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, + "util-extend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "integrity": "sha512-mLs5zAK+ctllYBj+iAQvlDCwoxU/WDOUaJkcFudeiAX6OajC6BKXJUa9a+tbtkC11dz2Ufb7h0lyvIOVn4LADA==" + }, "uvu": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz", diff --git a/package.json b/package.json index 553471ac..2115a05c 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "d3-shape": "^3.0.1", "gray-matter": "^4.0.3", "mapbox-gl": "^1.13.1", + "ndarray-concat-cols": "^1.0.0", "next": "^12.0.5", "next-mdx-remote": "^4.1.0", "react": "^18.2.0", From f6968aca38cd9b0a39147b88a3d208e17f4ba8d4 Mon Sep 17 00:00:00 2001 From: katamartin Date: Mon, 15 Jul 2024 14:08:31 -0400 Subject: [PATCH 07/11] Update OAE Efficiency tool logo --- components/tool-logos/oae-efficiency.js | 200 +++++------------------- 1 file changed, 35 insertions(+), 165 deletions(-) diff --git a/components/tool-logos/oae-efficiency.js b/components/tool-logos/oae-efficiency.js index 68bad6c8..36a7926f 100644 --- a/components/tool-logos/oae-efficiency.js +++ b/components/tool-logos/oae-efficiency.js @@ -13,226 +13,96 @@ const Logo = () => { return ( - - - - - - - - - - - - - - - - - - - - - - - - - - From dc90153b03c5916c4acf7d42f76233a26794fc00 Mon Sep 17 00:00:00 2001 From: katamartin Date: Mon, 15 Jul 2024 14:08:41 -0400 Subject: [PATCH 08/11] Update highlight date --- components/highlights.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/highlights.js b/components/highlights.js index 3b0e12e8..4a44a9e1 100644 --- a/components/highlights.js +++ b/components/highlights.js @@ -5,7 +5,7 @@ import Highlight from './highlight' const HIGHLIGHTS = [ { id: 'oae-efficiency', - date: '06-27-2024', + date: '07-16-2024', href: '/research/oae-efficiency-explainer', title: 'Mapping the efficiency of ocean alkalinity enhancement', summary: From 832dbb15ff36cba30bc50c5d61fa361af6165ffb Mon Sep 17 00:00:00 2001 From: katamartin Date: Mon, 15 Jul 2024 14:29:31 -0400 Subject: [PATCH 09/11] Update highlight to point towards tool --- components/highlights.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/highlights.js b/components/highlights.js index 4a44a9e1..667aaa82 100644 --- a/components/highlights.js +++ b/components/highlights.js @@ -6,7 +6,7 @@ const HIGHLIGHTS = [ { id: 'oae-efficiency', date: '07-16-2024', - href: '/research/oae-efficiency-explainer', + href: '/research/oae-efficiency', title: 'Mapping the efficiency of ocean alkalinity enhancement', summary: 'We developed a tool to explore a new dataset that makes it easier to see how the efficiency of ocean alkalinity enhancement varies around the world, in collaboration with [C]Worthy.', From e5fb069678c5b67590c5538b9b969a5b4ad92927 Mon Sep 17 00:00:00 2001 From: katamartin Date: Mon, 15 Jul 2024 14:30:47 -0400 Subject: [PATCH 10/11] Add article --- .../components/alk-chem-diagram.js | 511 ++++++++++++++++++ .../components/carb-chem-diagram.js | 472 ++++++++++++++++ .../components/carbonate-slider.js | 173 ++++++ .../components/chemistry.js | 23 + .../components/data.js | 70 +++ .../components/efficiencies-map.js | 175 ++++++ .../components/flux-map.js | 191 +++++++ .../components/icons/index.js | 2 + .../components/icons/pause.js | 19 + .../components/icons/play.js | 17 + .../components/modeling-methods.js | 144 +++++ .../components/physical-processes.js | 367 +++++++++++++ .../components/regional-comparison.js | 423 +++++++++++++++ .../components/time-slider.js | 114 ++++ articles/oae-efficiency-explainer/index.md | 279 ++++++++++ .../oae-efficiency-explainer/references.json | 106 ++++ components/mdx/page-components.js | 52 ++ 17 files changed, 3138 insertions(+) create mode 100644 articles/oae-efficiency-explainer/components/alk-chem-diagram.js create mode 100644 articles/oae-efficiency-explainer/components/carb-chem-diagram.js create mode 100644 articles/oae-efficiency-explainer/components/carbonate-slider.js create mode 100644 articles/oae-efficiency-explainer/components/chemistry.js create mode 100644 articles/oae-efficiency-explainer/components/data.js create mode 100644 articles/oae-efficiency-explainer/components/efficiencies-map.js create mode 100644 articles/oae-efficiency-explainer/components/flux-map.js create mode 100644 articles/oae-efficiency-explainer/components/icons/index.js create mode 100644 articles/oae-efficiency-explainer/components/icons/pause.js create mode 100644 articles/oae-efficiency-explainer/components/icons/play.js create mode 100644 articles/oae-efficiency-explainer/components/modeling-methods.js create mode 100644 articles/oae-efficiency-explainer/components/physical-processes.js create mode 100644 articles/oae-efficiency-explainer/components/regional-comparison.js create mode 100644 articles/oae-efficiency-explainer/components/time-slider.js create mode 100644 articles/oae-efficiency-explainer/index.md create mode 100644 articles/oae-efficiency-explainer/references.json diff --git a/articles/oae-efficiency-explainer/components/alk-chem-diagram.js b/articles/oae-efficiency-explainer/components/alk-chem-diagram.js new file mode 100644 index 00000000..7c26670b --- /dev/null +++ b/articles/oae-efficiency-explainer/components/alk-chem-diagram.js @@ -0,0 +1,511 @@ +import { Column, Row } from '@carbonplan/components' +import React from 'react' +import { Box, Flex, useThemeUI } from 'theme-ui' + +const AlkChemDiagram = () => { + const { theme } = useThemeUI() + + return ( + <> + + + + + Adding alkalinity shifts ocean carbon chemistry toward non-CO₂ + forms of carbon, driving uptake of CO₂ from the atmosphere. + + + This increases the ocean’s ability to store carbon, mainly in the + form of bicarbonate (HCO₃) ions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default AlkChemDiagram diff --git a/articles/oae-efficiency-explainer/components/carb-chem-diagram.js b/articles/oae-efficiency-explainer/components/carb-chem-diagram.js new file mode 100644 index 00000000..ce757d9a --- /dev/null +++ b/articles/oae-efficiency-explainer/components/carb-chem-diagram.js @@ -0,0 +1,472 @@ +import { Column, Row } from '@carbonplan/components' +import React from 'react' +import { Box, Flex, useThemeUI } from 'theme-ui' + +const CarbChemDiagram = () => { + const { theme } = useThemeUI() + + return ( + <> + + + + + The ocean and atmosphere exchange CO₂ to maintain equilibrium. The + more CO₂ we put in the atmosphere, the more CO₂ dissolves into the + ocean. + + + Natural ocean chemistry transforms some of this CO₂ into other + forms of carbon, increasing the total amount of carbon stored in + the ocean. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default CarbChemDiagram diff --git a/articles/oae-efficiency-explainer/components/carbonate-slider.js b/articles/oae-efficiency-explainer/components/carbonate-slider.js new file mode 100644 index 00000000..3346fc6a --- /dev/null +++ b/articles/oae-efficiency-explainer/components/carbonate-slider.js @@ -0,0 +1,173 @@ +import React from 'react' +import { Box, Flex, Label, Checkbox, Slider } from 'theme-ui' + +const CarbonateSlider = ({ + data, + slidableVariable, + varIndex, + setVarIndex, + equilibrated, + setEquilibrated, +}) => { + return ( + + {data.dic && ( + <> + + + + {data.dic[varIndex] > 0 + ? `+${data.dic[varIndex].toFixed()}` + : data.dic[varIndex].toFixed()} + + + Ocean carbon (DIC) + + + + + {data.ph[varIndex] > 0 + ? `+${data.ph[varIndex].toFixed(2)}` + : data.ph[varIndex].toFixed(2)} + + + pH + + + + + + + {data.co2[varIndex] > 0 + ? `+${data.co2[varIndex].toFixed()}` + : data.co2[varIndex].toFixed()} + + + CO₂ + + + + + {data.hco3[varIndex] > 0 + ? `+${data.hco3[varIndex].toFixed()}` + : data.hco3[varIndex].toFixed()} + + + HCO₃ + + + + + {data.co3[varIndex] > 0 + ? `+${data.co3[varIndex].toFixed()}` + : data.co3[varIndex].toFixed()} + + + CO₃ + + + + + )} + + (∆µmol / kg seawater) + + + setVarIndex(parseFloat(e.target.value))} + min={0} + max={ + data && slidableVariable.key in data + ? Object.keys(data[slidableVariable.key]).length - 1 + : 0 + } + step={1} + /> + + + + + + {data[slidableVariable.key] && + data[slidableVariable.key][varIndex].toFixed(0)} + + {slidableVariable.name} + {equilibrated !== undefined && ( + + )} + + + ) +} + +export default CarbonateSlider diff --git a/articles/oae-efficiency-explainer/components/chemistry.js b/articles/oae-efficiency-explainer/components/chemistry.js new file mode 100644 index 00000000..18c681c6 --- /dev/null +++ b/articles/oae-efficiency-explainer/components/chemistry.js @@ -0,0 +1,23 @@ +import { Box } from 'theme-ui' + +export const HCO3 = () => { + return ( + <> + HCO₃ + + ⁻ + + + ) +} + +export const CO3 = () => { + return ( + <> + CO₃ + + ²⁻ + + + ) +} diff --git a/articles/oae-efficiency-explainer/components/data.js b/articles/oae-efficiency-explainer/components/data.js new file mode 100644 index 00000000..a1b2e86a --- /dev/null +++ b/articles/oae-efficiency-explainer/components/data.js @@ -0,0 +1,70 @@ +import { createContext, useContext, useEffect, useState } from 'react' +import { feature } from 'topojson-client' +import zarr from 'zarr-js' + +const DataContext = createContext({}) + +export const DataWrapper = ({ children }) => { + const [efficiencies, setEfficiencies] = useState({}) + const [regions, setRegions] = useState() + const [loader, setLoader] = useState(null) + + useEffect(() => { + zarr().open( + 'https://carbonplan-oae-efficiency.s3.us-west-2.amazonaws.com/store1b.zarr/OAE_efficiency', + (err, get) => { + setLoader(() => get) + } + ) + }, []) + + return ( + + {children} + + ) +} + +export const useEfficiency = (injectionMonth) => { + const { efficiencies, loader, setEfficiencies } = useContext(DataContext) + + useEffect(() => { + if (!efficiencies[injectionMonth] && loader) { + setEfficiencies((prev) => ({ ...prev, [injectionMonth]: 'loading' })) + loader([0, 0, injectionMonth], (innerErr, array) => { + setEfficiencies((prev) => ({ ...prev, [injectionMonth]: array })) + }) + } + }, [efficiencies, setEfficiencies, injectionMonth, loader]) + + return { + efficiency: + efficiencies[injectionMonth] === 'loading' + ? null + : efficiencies[injectionMonth], + } +} + +export const useRegions = () => { + const { regions, setRegions } = useContext(DataContext) + + useEffect(() => { + if (!regions) { + fetch( + 'https://carbonplan-oae-efficiency.s3.us-west-2.amazonaws.com/regions.topojson' + ) + .then((response) => response.json()) + .then((topojsonData) => { + const geojsonData = feature( + topojsonData, + topojsonData.objects.regions + ) + setRegions(geojsonData) + }) + } + }, [regions, setRegions]) + + return { regions: regions === 'loading' ? null : regions } +} diff --git a/articles/oae-efficiency-explainer/components/efficiencies-map.js b/articles/oae-efficiency-explainer/components/efficiencies-map.js new file mode 100644 index 00000000..ff9f5673 --- /dev/null +++ b/articles/oae-efficiency-explainer/components/efficiencies-map.js @@ -0,0 +1,175 @@ +import { Minimap, Path, useMinimap } from '@carbonplan/minimaps' +import { naturalEarth1 } from '@carbonplan/minimaps/projections' +import React, { useEffect, useState } from 'react' +import { geoPath } from 'd3-geo' + +import { Box, Flex, useThemeUI } from 'theme-ui' +import { useThemedColormap } from '@carbonplan/colormaps' +import { Colorbar, Column, Filter, Row } from '@carbonplan/components' +import TimeSlider from './time-slider' +import { useEfficiency, useRegions } from './data' + +const getColor = (polygon_id, efficiencies, colormap) => { + if (!efficiencies) { + return null + } + + const index = Number(polygon_id) + const efficiency = efficiencies.get(index) + + const rgb = colormap[Math.round(efficiency * (colormap.length - 1))] ?? [] + + return `rgb(${rgb.join(',')})` +} + +const Regions = ({ colormap, injectionMonth, time }) => { + const { projection } = useMinimap() + const [regions, setRegions] = useState({}) + const [efficiencies, setEfficiencies] = useState() + const { efficiency } = useEfficiency(injectionMonth) + const { regions: regionsGeojson } = useRegions() + + useEffect(() => { + if (efficiency) { + setEfficiencies(efficiency.pick(time, null, 0)) + } + }, [efficiency, time]) + + useEffect(() => { + if (regionsGeojson) { + setRegions( + regionsGeojson.features.reduce((a, f) => { + const id = f.properties.polygon_id + const path = geoPath(projection)(f) + // append paths for multipart geometries + if (a[id]) { + a[id] = a[id] + ' ' + path + } else { + a[id] = path + } + return a + }, {}) + ) + } + }, [regionsGeojson, projection]) + + return ( + <> + {Object.keys(regions).map((polygon_id) => ( + + ))} + + ) +} + +const MONTH_LABELS = { + Jan: 0, + Apr: 1, + Jul: 2, + Oct: 3, +} + +const formatTime = (t) => { + return `Y${Math.floor(t / 12) + 1} M${(t % 12) + 1}` +} +const EfficienciesMap = () => { + const { theme } = useThemeUI() + const [injectionMonth, setInjectionMonth] = useState(0) + const [time, setTime] = useState(179) + const colormap = useThemedColormap('cool') + + return ( + + + + + Elapsed time + + + + + + + + + Injection month + + + + setInjectionMonth( + MONTH_LABELS[Object.keys(obj).find((k) => obj[k])] + ) + } + sx={{ mt: 3 }} + /> + + + + + + + + + + + + + + ) +} + +export default EfficienciesMap diff --git a/articles/oae-efficiency-explainer/components/flux-map.js b/articles/oae-efficiency-explainer/components/flux-map.js new file mode 100644 index 00000000..43bacde9 --- /dev/null +++ b/articles/oae-efficiency-explainer/components/flux-map.js @@ -0,0 +1,191 @@ +import React, { useCallback, useEffect, useState, useMemo, useRef } from 'react' +import { Minimap, Path, Sphere, Raster } from '@carbonplan/minimaps' +import { naturalEarth1 } from '@carbonplan/minimaps/projections' +import { useThemedColormap } from '@carbonplan/colormaps' +import { Colorbar, Column, Row, formatDate } from '@carbonplan/components' +import zarr from 'zarr-js' +import { Box, Flex, useThemeUI } from 'theme-ui' + +import TimeSlider from './time-slider' + +const SOURCE = + 'https://carbonplan-oae-efficiency.s3.us-west-2.amazonaws.com/fgco2-2021-180x360.zarr' +const VARIABLE = 'FG_CO2_2' + +const CLIM = [-5, 5] +const MAX_CHUNK_KEY = 12 +const FILL_VALUE = 9.969209968386869e36 + +const getCustomProjection = () => { + return { + ...naturalEarth1(), + glsl: { + func: ` + vec2 naturalEarth1Invert(float x, float y) + { + const float pi = 3.14159265358979323846264; + const float halfPi = pi * 0.5; + float phi = y; + float delta; + float phi2 = phi * phi; + float phi4 = phi2 * phi2; + for (int i = 0; i < 25; i++) { + phi2 = phi * phi; + phi4 = phi2 * phi2; + delta = (phi * (1.007226 + phi2 * (0.015085 + phi4 * (-0.044475 + 0.028874 * phi2 - 0.005916 * phi4))) - y) / (1.007226 + phi2 * (0.015085 * 3.0 + phi4 * (-0.044475 * 7.0 + 0.028874 * 9.0 * phi2 - 0.005916 * 11.0 * phi4))); + phi = phi - delta; + if (abs(delta) < 1e-6) { + break; + } + } + phi2 = phi * phi; + float lambda = x / (0.8707 + phi2 * (-0.131979 + phi2 * (-0.013791 + phi2 * phi2 * phi2 * (0.003971 - 0.001529 * phi2)))); + if (lambda <= -1.0 * pi + 1e-6 || lambda >= pi - 1e-6) { + return vec2(-1000.0, -1000.0); + } else { + return vec2(degrees(lambda), degrees(phi)); + } + } + `, + name: 'naturalEarth1Invert', + }, + } +} + +// const useCustomColormap = () => { +// const fire = useThemedColormap('fire', { count: 127 }) +// const water = useThemedColormap('water', { count: 127 }) + +// return useMemo(() => { +// return [...[...fire].reverse(), ...water] +// }, [fire, water]) +// } + +const FluxMap = () => { + const { theme } = useThemeUI() + const colormap = useThemedColormap('orangeblue') + const flipped = useMemo(() => [...colormap].reverse(), [colormap]) + const [time, setTime] = useState(0) + const [chunkCache, setChunkCache] = useState({}) + const fetchChunk = useRef(null) + + useEffect(() => { + const fetchGroup = async () => { + try { + zarr().openGroup(SOURCE, (err, { [VARIABLE]: variableLoader }) => { + if (err) { + console.error('Error opening group:', err) + return + } + fetchChunk.current = (chunkKey) => { + setChunkCache((prev) => ({ ...prev, [chunkKey]: 'loading' })) + variableLoader([chunkKey, 0, 0], (err, chunk) => { + if (err) { + console.error('Error loading chunk:', err) + return + } + setChunkCache((prev) => ({ ...prev, [chunkKey]: chunk })) + }) + } + + fetchChunk.current(0) + }) + } catch (error) { + console.error('Error fetching group:', error) + } + } + fetchGroup() + }, []) + + useEffect(() => { + if (!fetchChunk.current) { + return + } + + const chunkKey = Math.floor(time / 30) + if (!chunkCache[chunkKey]) { + fetchChunk.current(chunkKey) + } + const nextChunkKey = chunkKey + 1 + if (nextChunkKey <= MAX_CHUNK_KEY && !chunkCache[nextChunkKey]) { + fetchChunk.current(nextChunkKey) + } + }, [chunkCache, time]) + + const data = useMemo(() => { + const chunkKey = Math.floor(time / 30) + if (chunkCache[chunkKey] && chunkCache[chunkKey] !== 'loading') { + const index = time % 30 + return chunkCache[chunkKey].pick(index, null, null) + } else { + return + } + }, [chunkCache, time]) + + const formatter = useCallback((t) => { + const date = new Date(2021, 0, 1 + t) + return formatDate( + `${date.getMonth() + 1}-${date.getDate()}-${date.getFullYear()}` + ) + }, []) + + return ( + + + + + + + + + + + {data && ( + + )} + + + + (d < 0 ? d : `+${d}`)} + label='Flux' + units='mol / m² / year' + horizontal + sx={{ flexShrink: 0 }} + /> + + + + ) +} + +export default FluxMap diff --git a/articles/oae-efficiency-explainer/components/icons/index.js b/articles/oae-efficiency-explainer/components/icons/index.js new file mode 100644 index 00000000..b27a871a --- /dev/null +++ b/articles/oae-efficiency-explainer/components/icons/index.js @@ -0,0 +1,2 @@ +export { default as Play } from './play' +export { default as Pause } from './pause' diff --git a/articles/oae-efficiency-explainer/components/icons/pause.js b/articles/oae-efficiency-explainer/components/icons/pause.js new file mode 100644 index 00000000..188ca61a --- /dev/null +++ b/articles/oae-efficiency-explainer/components/icons/pause.js @@ -0,0 +1,19 @@ +import { Box } from 'theme-ui' + +const Pause = (props) => { + return ( + + + + + ) +} + +export default Pause diff --git a/articles/oae-efficiency-explainer/components/icons/play.js b/articles/oae-efficiency-explainer/components/icons/play.js new file mode 100644 index 00000000..079195c0 --- /dev/null +++ b/articles/oae-efficiency-explainer/components/icons/play.js @@ -0,0 +1,17 @@ +import { Box } from 'theme-ui' + +const Play = (props) => { + return ( + + + + ) +} + +export default Play diff --git a/articles/oae-efficiency-explainer/components/modeling-methods.js b/articles/oae-efficiency-explainer/components/modeling-methods.js new file mode 100644 index 00000000..31261d72 --- /dev/null +++ b/articles/oae-efficiency-explainer/components/modeling-methods.js @@ -0,0 +1,144 @@ +import { useThemeUI } from 'theme-ui' + +const ModelingMethods = () => { + const { theme } = useThemeUI() + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default ModelingMethods diff --git a/articles/oae-efficiency-explainer/components/physical-processes.js b/articles/oae-efficiency-explainer/components/physical-processes.js new file mode 100644 index 00000000..b7f5ab09 --- /dev/null +++ b/articles/oae-efficiency-explainer/components/physical-processes.js @@ -0,0 +1,367 @@ +import { useThemeUI } from 'theme-ui' + +const PhysicalProcesses = () => { + const { theme } = useThemeUI() + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} + +export default PhysicalProcesses diff --git a/articles/oae-efficiency-explainer/components/regional-comparison.js b/articles/oae-efficiency-explainer/components/regional-comparison.js new file mode 100644 index 00000000..b7f9894e --- /dev/null +++ b/articles/oae-efficiency-explainer/components/regional-comparison.js @@ -0,0 +1,423 @@ +import { Badge, Colorbar, Column, Filter, Row } from '@carbonplan/components' +import { + Graticule, + Minimap, + Path, + Raster, + Sphere, + useMinimap, +} from '@carbonplan/minimaps' +import { naturalEarth1 } from '@carbonplan/minimaps/projections' +import { useThemedColormap } from '@carbonplan/colormaps' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { Box, Flex, useThemeUI } from 'theme-ui' +import { geoPath } from 'd3-geo' +import zarr from 'zarr-js' +import concat from 'ndarray-concat-cols' +import { Chart, Plot, Line, Grid } from '@carbonplan/charts' +import { mix } from '@theme-ui/color' + +import { useEfficiency, useRegions } from './data' +import TimeSlider from './time-slider' + +const sx = { + column: { + borderWidth: 0, + borderTopWidth: '1px', + borderColor: 'muted', + borderStyle: 'solid', + pt: [2, 2, 3, 3], + mb: [3, 3, 4, 4], + }, + heading: { + fontFamily: 'heading', + letterSpacing: 'smallcaps', + textTransform: 'uppercase', + fontSize: [2, 2, 2, 3], + mb: [2, 2, 3, 3], + wordSpacing: ['300px', '300px', 'inherit', 'inherit'], + }, + value: { + textTransform: 'uppercase', + fontFamily: 'mono', + letterSpacing: 'mono', + fontSize: [3, 3, 3, 4], + }, + details: { + mt: 2, + color: 'secondary', + fontFamily: 'faux', + letterSpacing: 'faux', + fontSize: [0, 1, 1, 1], + }, +} + +const MONTH_LABELS = { + Jan: 0, + Apr: 1, + Jul: 2, + Oct: 3, +} + +const POLYGONS = [74, 131, 126, 106, 140, 119, 107, 124, 116] +const SOURCE = + 'https://carbonplan-oae-efficiency.s3.us-west-2.amazonaws.com/store3.zarr/delta_FG_CO2' +const CLIM = [0, -1e-2].map((d) => d / -315.36) +const FILL_VALUE = 9.969209968386869e36 +const BOUNDS = { + lat: [-90, 90], + lon: [-180, 180], +} + +const Regions = ({ region, setRegion, setHoveredRegion, hoveredRegion }) => { + const { regions } = useRegions() + const [paths, setPaths] = useState({}) + const { projection } = useMinimap() + + useEffect(() => { + if (regions) { + setPaths( + regions.features.reduce((a, f) => { + if (POLYGONS.includes(f.properties.polygon_id)) { + a[f.properties.polygon_id] = geoPath(projection)(f) + } + return a + }, {}) + ) + } + }, [regions, projection]) + + const { unselected, selected, hovered } = useMemo(() => { + return Object.keys(paths).reduce( + (accum, polygon_id) => { + if (region === Number(polygon_id)) { + accum.selected = paths[polygon_id] + } else if (hoveredRegion === Number(polygon_id)) { + accum.hovered = { polygon_id, path: paths[polygon_id] } + } else { + accum.unselected[polygon_id] = paths[polygon_id] + } + + return accum + }, + { unselected: {}, hovered: null, selected: null } + ) + }, [paths, region, hoveredRegion]) + + return ( + <> + {Object.keys(unselected).map((polygon_id) => ( + setRegion(polygon_id)} + onMouseEnter={() => setHoveredRegion(polygon_id)} + onMouseLeave={() => setHoveredRegion(null)} + sx={{ + fill: 'none', + stroke: 'secondary', + strokeWidth: 2, + pointerEvents: 'all', + cursor: 'pointer', + }} + /> + ))} + {selected && ( + + )} + {hovered && ( + setRegion(hovered.polygon_id)} + onMouseLeave={() => setHoveredRegion(null)} + sx={{ + fill: mix('primary', 'background', 0.7), + stroke: 'primary', + strokeWidth: 2, + pointerEvents: 'all', + cursor: 'pointer', + }} + /> + )} + + ) +} + +const MAP_PROPS = { scale: 1.7, translate: [0.25, 0.5] } + +const formatTime = (t) => { + return `Year ${String(t + 1).padStart(2, '0')}` +} + +const RegionalComparison = () => { + const { theme } = useThemeUI() + const [region, setRegion] = useState(119) + const [hoveredRegion, setHoveredRegion] = useState(119) + const [injectionMonth, setInjectionMonth] = useState(0) + const { efficiency } = useEfficiency(injectionMonth) + const [time, setTime] = useState(0) + const [chunkCache, setChunkCache] = useState({}) + const fetchChunk = useRef(null) + const colormap = useThemedColormap('warm') + + const { selectedLine, hoveredLine, backgroundLines } = useMemo(() => { + if (efficiency) { + return POLYGONS.reduce( + (accum, p) => { + const ndData = efficiency.pick(null, p, 0) + const line = Array(180) + .fill(null) + .map((d, i) => [i / 12, ndData.get(i)]) + + if (p === region) { + accum.selectedLine = line + } else if (p === hoveredRegion) { + accum.hoveredLine = line + } else { + accum.backgroundLines.push(line) + } + + return accum + }, + { selectedLine: null, hoveredLine: null, backgroundLines: [] } + ) + } else { + return {} + } + }, [efficiency, region, hoveredRegion]) + + useEffect(() => { + const openArray = async () => { + try { + zarr().open(SOURCE, (err, loader) => { + if (err) { + console.error('Error opening array:', err) + return + } + fetchChunk.current = (key) => { + const [regionIndex, injectionMonthIndex] = key + .split(',') + .map(Number) + setChunkCache((prev) => ({ ...prev, [key]: 'loading' })) + loader( + [regionIndex, injectionMonthIndex, 0, 0, 0], + (err, chunk) => { + if (err) { + console.error('Error loading chunk:', err) + return + } + setChunkCache((prev) => ({ ...prev, [key]: chunk })) + } + ) + } + + fetchChunk.current('5,0') + }) + } catch (error) { + console.error('Error fetching group:', error) + } + } + openArray() + }, []) + + useEffect(() => { + if (!fetchChunk.current) { + return + } + + const key = [POLYGONS.indexOf(region), injectionMonth].join(',') + + if (!chunkCache[key]) { + fetchChunk.current(key) + } + }, [chunkCache, region, injectionMonth]) + + const data = useMemo(() => { + const key = [POLYGONS.indexOf(region), injectionMonth].join(',') + if (chunkCache[key] && chunkCache[key] !== 'loading') { + // dims: ['polygon_id', 'injection_date', 'elapsed_time', 'y', 'x'] + const result = chunkCache[key].pick(0, 0, time, null, null) + + // Slice out column at index=125 in x dimension to remove artifact from original data grid + const refined = concat([result.hi(180, 124), result.lo(0, 125)], { + dtype: 'float32', + }) + return refined + } else { + return + } + }, [chunkCache, time, region, injectionMonth]) + + const handleSetRegion = useCallback((id) => { + setRegion(Number(id)) + setTime(0) + }, []) + + const handleSetHoveredRegion = useCallback((id) => { + setHoveredRegion(Number(id)) + }, []) + + return ( + + + + + + Region + {String(region).padStart(3, '0')} + + + + + + + + + + + + + + + + + + + Injection month + + { + setInjectionMonth( + MONTH_LABELS[Object.keys(obj).find((k) => obj[k])] + ) + setTime(0) + }} + /> + + + + Elapsed time + + + + + Efficiency + + + {selectedLine && + selectedLine[selectedLine.length - 1][1].toFixed(2)} + + after 15 years + + + + + {backgroundLines && + backgroundLines.map((l, i) => ( + + ))} + {selectedLine && ( + + )} + {hoveredLine && ( + + )} + + + + + + + ) +} + +export default RegionalComparison diff --git a/articles/oae-efficiency-explainer/components/time-slider.js b/articles/oae-efficiency-explainer/components/time-slider.js new file mode 100644 index 00000000..c212cc0c --- /dev/null +++ b/articles/oae-efficiency-explainer/components/time-slider.js @@ -0,0 +1,114 @@ +import React, { useCallback, useState, useRef, useEffect } from 'react' +import { Slider, Button } from '@carbonplan/components' + +import { Play, Pause } from './icons' + +const TimeSlider = ({ + delay = 100, + formatDate, + time, + setTime, + min = 0, + max, + disabled, + pause = 'min', + autoPlay = false, + setAutoPlay, +}) => { + const [playing, setPlaying] = useState(false) + const timeout = useRef(null) + + const handlePlay = useCallback( + (willPlay) => { + if (timeout.current) { + clearTimeout(timeout.current) + timeout.current = null + } + + setPlaying(willPlay) + if (willPlay) { + const incrementTime = (alwaysIncrement = false) => { + timeout.current = setTimeout(() => { + setTime((prev) => { + let nextValue = prev + 1 + if (pause === 'max' && nextValue === max && !alwaysIncrement) { + setPlaying(false) + } else if (nextValue > max) { + nextValue = min + if (pause === 'min' && !alwaysIncrement) { + setPlaying(false) + } else { + incrementTime() + } + } else { + incrementTime() + } + return nextValue + }) + }, delay) + } + incrementTime(true) + } + }, + [min, max, pause, delay, setTime] + ) + + const handleSetTime = useCallback( + (e) => { + setTime(parseFloat(e.target.value)) + handlePlay(false) + }, + [setTime, handlePlay] + ) + + useEffect(() => { + if (autoPlay) { + handlePlay(true) + setAutoPlay(false) + } + }, [autoPlay, handlePlay, setAutoPlay]) + + useEffect(() => { + if (disabled) { + setPlaying(false) + clearTimeout(timeout.current) + setAutoPlay && setAutoPlay(false) + } + }, [disabled, setAutoPlay]) + + return ( + <> + + + + ) +} + +export default TimeSlider diff --git a/articles/oae-efficiency-explainer/index.md b/articles/oae-efficiency-explainer/index.md new file mode 100644 index 00000000..3e532c2f --- /dev/null +++ b/articles/oae-efficiency-explainer/index.md @@ -0,0 +1,279 @@ +--- +version: 1.0.0 +title: Mapping the efficiency of ocean alkalinity enhancement +authors: + - Matthew C. Long + - Freya Chay + - Mengyang Zhou + - Michael Tyka + - Shane Loeffler + - Kata Martin + - Thomas Nicholas + - Elizabeth Yankovsky + - David Ho + - Alicia Karspeck +color: blue +date: 07-16-2024 +summary: Increasing the alkalinity of the ocean can help increase CO₂ absorption. But the same techniques won’t lead to the same outcomes everywhere. We collaborated with [C]Worthy to build a tool that will make it easier to see where ocean alkalinity enhancement is most efficient. +quickLook: This new dataset and tool make it easier to see how the efficiency of ocean alkalinity enhancement varies around the world. Developed in collaboration with [C]Worthy. +card: oae-efficiency-explainer +background: articles/026/droplet +icon: articles/026/droplet-small +components: + - name: FluxMap + src: ./components/flux-map.js + - name: PhysicalProcesses + src: ./components/physical-processes.js + - name: ModelingMethods + src: ./components/modeling-methods.js + - name: EfficienciesMap + src: ./components/efficiencies-map.js + - name: RegionalComparison + src: ./components/regional-comparison.js + - name: AlkChemDiagram + src: ./components/alk-chem-diagram.js + - name: CarbChemDiagram + src: ./components/carb-chem-diagram.js + - name: DataWrapper + src: ./components/data.js + - name: HCO3 + src: ./components/chemistry.js + - name: CO3 + src: ./components/chemistry.js +links: + - label: Map tool + href: /research/oae-efficiency + - label: Preprint + href: https://doi.org/10.21203/rs.3.rs-4124909/v1 + - label: Dataset + href: https://beta.source.coop/repositories/cworthy/oae-efficiency-atlas/description/ +--- + + +The ocean plays an essential role in the global carbon cycle. It stores about 38,000 billion metric tons of carbon, making it the largest active reservoir of carbon on the planet. It also soaks up about one quarter of the CO₂ emitted annually by humans. Scientists and engineers are currently exploring how to amplify the ocean’s natural ability to absorb and store carbon. One promising approach is called ocean alkalinity enhancement (OAE). OAE mimics natural geochemical processes that shift ocean chemistry to remove CO₂ from the atmosphere. This could be a highly scalable approach to carbon dioxide removal (CDR), but making it work requires a rigorous understanding of ocean processes and how they vary over time and space. + +OAE relies on adding alkaline materials, like crushed rocks or hydroxides, to the surface ocean — but this action alone does not guarantee carbon removal.Strictly speaking, electrochemical OAE methods actually remove acid from the surface ocean, but this is functionally equivalent to adding a base such as hydroxide. Instead, these materials shift the chemistry of the water, making it able to absorb and store more CO₂. Although this initial chemical shift happens quickly, it takes time for the ocean to absorb CO₂ from the atmosphere. Since the ocean is always in motion, carbon removal can happen far from where alkalinity is added. Furthermore, if ocean circulation moves the alkalinity-treated water away from the surface and out of contact with the atmosphere, the process of absorbing atmospheric CO₂ can be cut short. Natural variations in these physical circulation dynamics mean that alkalinity deployed in different locations or at different times of the year can result in different amounts of carbon removal. Understanding these dynamics is critical for deciding where and when it makes sense to pursue OAE, and estimating how much carbon actually gets removed from the atmosphere. + +The OAE Efficiency Map is a new tool for understanding these dynamics and informing related decisions. Using a global ocean biogeochemical model, [[C]Worthy](https://cworthy.org/) and collaborators simulated how efficiently OAE leads to carbon removal and its dependence on the location and season in which the alkaline materials are added to the ocean, and described the results in a [scientific paper](https://doi.org/10.21203/rs.3.rs-4124909/v1). The “efficiency” of OAE is defined as the amount of CO₂ that will be transferred from the atmosphere to the ocean per unit of alkalinity added. Together, [C]Worthy and CarbonPlan have turned this dataset into an [interactive online tool](/research/oae-efficiency). With it, you can explore global patterns in OAE efficiency, and drill down to visualize how alkalinity released in a specific region and season will move through the ocean and result in carbon removal over time. + +Scientists, companies, policymakers, and society at large are all still learning about OAE — both its potential as a carbon removal strategy and its safety for ocean ecosystems. We hope this tool helps build intuition about how OAE works, supports smart decision-making about real-world deployments, and informs ongoing efforts to create scientifically informed standards and effective regulatory frameworks for ocean-based CDR. + +## Introduction to Ocean Alkalinity Enhancement + +If you’re new to OAE, there are a few foundational concepts that are important to understand in order to interpret our methods and effectively use the new tool. + +### 01 — The ocean stores enormous amounts of carbon and constantly exchanges CO₂ with the atmosphere. + +CO₂ is constantly being passed back and forth between the ocean and the atmosphere to maintain equilibrium — a state in which the concentration of dissolved CO₂ at the surface of the ocean is in balance with the amount of CO₂ gas in the atmosphere.Notably, the deep ocean does not stay close to equilibrium with the atmosphere, which is one reason the ocean can store so much carbon. When ocean circulation brings deep water to the surface, it can exchange CO₂ with the atmosphere. However, since the ocean is stratified and of such large volume, ventilating the deep ocean requires hundreds to thousands of years. Each year, around 330 billion metric tons (petagrams) of CO₂ are absorbed and released by the ocean, a massive exchange of carbon with the atmosphere that includes strong regional and seasonal patterns (Figure 1). But these massive fluxes of carbon in and out of the ocean don’t perfectly balance. Because human-derived emissions have increased the amount of CO₂ in the atmosphere, the ocean absorbs an additional 10 petagrams of anthropogenic CO₂ annually. + +
+ + + Historical simulation of the exchange of CO₂ between the ocean and + atmosphere. These are data from a high-resolution (0.1° x 0.1°) numerical + simulation using the [Community Earth System + Model](https://www.cesm.ucar.edu/). + Negative values indicate that CO₂ is being transferred + into the ocean, while positive values indicate transfer of CO₂ out of the ocean + and into the atmosphere. The patterns in this animation reflect the combined + influence of ocean circulation and mixing, biological productivity, surface warming + and cooling, and variations in the winds. + +
+ +Air-sea gas exchange ensures that the concentration of CO₂ in the surface ocean is approximately in balance with CO₂ in the atmosphere — but the ocean stores much more carbon than we would expect if all the carbon was in the form of dissolved CO₂ gas. When CO₂ dissolves in seawater, it forms a weak acid called carbonic acid (H₂CO₃), which dissociates to form bicarbonate () and carbonate () ions. Only about 1% of the carbon in the ocean is CO₂ — the majority is stored in the form of bicarbonate (~90%) and carbonate (~10%) ions. Unlike CO₂, bicarbonate and carbonate ions cannot directly exchange with the atmosphere and storing carbon in these forms increases the ocean’s total carbon storage capacity. The chemical reactions relating CO₂, bicarbonate, and carbonate ions are referred to as “carbonate chemistry.” + +
+ + + Schematic of air-sea CO₂ transfer and seawater carbonate chemistry.{' '} + +
+ +Together, the sum of dissolved CO₂, bicarbonate, and carbonate ions is referred to as dissolved inorganic carbon (DIC). The balance between dissolved CO₂, bicarbonate, and carbonate — and, as a result, the total quantity of DIC that is in equilibrium with a given amount of CO₂ in the atmosphere — is controlled by the pH of seawater. Relatively more bicarbonate and carbonate ions are stored per mole of dissolved CO₂ when seawater has a higher pH (more basic) as compared to a lower pH (more acidic). Put another way, adding acid shifts the system toward dissolved CO₂, while adding a base shifts the system toward bicarbonate and carbonate ions. Importantly, adding dissolved CO₂ to the ocean — and the subsequent formation of carbonic acid — lowers the pH of seawater. This phenomenon is known as ocean acidification, and, in addition to providing an important feedback on the carbonate chemistry relationships described above, it has direct implications for marine organisms that are sensitive to pH. + +### 02 — Adding alkaline materials shifts seawater chemistry, and creates space for the ocean to absorb more CO₂. + +Adding alkaline materials to the ocean raises the pH of the solution. By raising the pH, alkaline materials allow the carbonate chemistry system to shift toward bicarbonate and carbonate ions. This creates a deficit in dissolved CO₂, which is replenished as CO₂ is transferred from the atmosphere to the ocean to restore equilibrium. Thus, OAE achieves carbon removal through air-sea CO₂ re-equilibration. If re-equilibration is fully achieved, dissolved CO₂ and pH values return to near their starting state, but the overall quantity of carbon stored in the ocean will have increased. + +
+ + + Schematic showing how adding alkalinity to seawater affects ocean carbon + storage.{' '} + +
+ +The maximum possible carbon removal that can be achieved by adding alkalinity to the ocean is determined by how much additional carbon would be dissolved if the seawater was permitted to fully re-equilibrate with the atmosphere. Perhaps counterintuitively, this potential differs based on where you are in the ocean. In the tropics, for example, adding one mole of alkalinity can be expected to achieve a maximum uptake of about 0.7 to 0.8 moles of carbon. High latitude regions have a greater maximum efficiency, closer to 0.9 moles of carbon per mole alkalinity. Estimates like these are referred to as the “thermodynamic maximum efficiency” of OAE. The differences in maximum efficiency are explained by differences in the temperature, salinity, and background chemistry at the surface ocean. + +### 03 — Physical processes in the ocean influence how much CO₂ is ultimately transferred from the atmosphere to the ocean after alkaline materials are added. + +Although it’s easy to calculate the maximum potential carbon removal from an alkalinity addition, the physical dynamics of the ocean — like surface turbulence, ocean currents, and vertical mixing — play an important role in determining whether that maximum potential efficiency is achieved. + +Air-sea CO₂ equilibration in response to an alkalinity addition takes time because it requires diffusing molecules from the air into the water. Furthermore, the carbonate chemistry of seawater means that CO₂ equilibration takes much longer than the equilibration for other gasses, such as oxygen (O₂). Because most of the CO₂ transferred into the ocean ends up as bicarbonate and carbonate ions, about 20 moles of CO₂ must be absorbed from the atmosphere to get a 1 mole change in the dissolved CO₂ in the ocean.Similar to the thermodynamic maximum efficiency, this ratio — the amount of CO₂ transfer required to change the dissolved CO₂ concentration — varies as a function of latitude due to differences in surface ocean carbon chemistry. At high latitudes, less CO₂ transfer is required to change the dissolved CO₂ concentration, hence the gas exchange equilibration timescale tends to be shorter than in the tropics. While carbonate chemistry defines the amount of CO₂ that’s necessary to transfer to achieve equilibrium, the rate of gas exchange, called the gas transfer velocity, is dependent on wind speed. Winds drive turbulence and create bubbles in the surface ocean. Higher winds more effectively refresh the water at the air-sea interface and create more bubbles, accelerating air-sea gas exchange. + +Since air-sea gas equilibration takes a long time and the ocean is constantly moving, CO₂ uptake from the atmosphere doesn’t just happen in one place. Alkalinity added to the ocean is transported away from the source region by ocean currents. Since reaching equilibrium takes time, the CO₂ absorption following an OAE deployment has the potential to happen over a very large region. And if alkalinity is removed from the surface ocean, air-sea gas equilibration can be cut short. This is a particular concern in areas where surface waters are subducting and in high-latitude regions where high winds and cold surface conditions drive energetic vertical mixing. + +
+ + + Schematic representation of the factors controlling OAE efficiency. The rate + of CO₂ gas equilibration (left column) is determined by the gas transfer + velocity, which depends on wind speed. Since CO₂ gas equilibration takes a + long time, ocean currents can distribute the added alkalinity — and hence + the CO₂ uptake — over large regions (middle column). Finally, removal of + alkalinity from the surface ocean by vertical mixing or subduction shuts off + CO₂ gas exchange (right column), limiting the total CO₂ uptake and OAE + efficiency. + +
+## Creating the OAE Efficiency Dataset We created the OAE efficiency dataset to explore +how adding alkalinity to the ocean at different locations and seasons results in +diverse carbon removal outcomes. In this dataset, we define OAE efficiency as the +amount of CO₂ that is transferred from the atmosphere to the ocean per unit of alkalinity +added.Note that this dataset does not consider the CO₂ emissions associated with the upstream energy and material handling requirements needed to deliver alkalinity to the ocean — it just describes the effect on ocean CO₂ uptake once alkalinity has been added to the ocean. + +To model OAE efficiency, we used a coarse-resolution global ocean circulation model from the [Community Earth System Model](https://www.cesm.ucar.edu/).The model we used has a horizontal resolution (grid spacing) of about 100 km, which is a fairly standard resolution for models used for climate projections. We first divided the ocean surface into regions of approximately similar size. To do so, we used a machine learning algorithm ([K-means clustering](https://github.com/CWorthy-ocean/oae-dor-global-efficiency/blob/main/analysis/Polygons.ipynb)) to fill each ocean basin with polygons of approximately similar surface areas. We delineated the exclusive economic zonesThe exclusive economic zones are defined by the region within 200 nautical miles of a country’s coastline. separately and filled these regions with more, smaller polygons to improve the resolution along coastlines. Next, we conducted a 15-year OAE simulation for each polygon in each of the four seasons. During the initial month of these simulations, we released alkalinity uniformly over the surface of the polygon at a rate of 10 mol m⁻² yr⁻¹.The efficiency curves computed by the model are not strongly dependent on the magnitude of this flux, since the carbonate system is approximately linear over a broad range of perturbations. Using another model, [He and Tyka (2023)](https://doi.org/10.5194/bg-20-27-2023) showed that an injection rate of 10 mol m⁻² yr⁻¹ does not raise the local pH beyond about 0.1 units and we confirmed that this result holds in our model. Thus, at this injection rate, carbonate saturation levels do not incur substantial risk of precipitation. The practicality of delivering this quantity of alkalinity to the ocean is a separate question. [He and Tyka (2023)](https://doi.org/10.5194/bg-20-27-2023) also examined ship-based alkalinity delivery. Given the size of the polygons used in this study, the alkalinity addition rate of 10 mol m⁻² yr⁻¹ could be sustained by 4–72 ships operating within each region, presuming a release of liquid or readily-dissolved material. We then ran the model forward in time to simulate the movement of the perturbed water and the ensuing difference in air-sea CO₂ equilibration relative to a simulation where no OAE intervention took place. + +
+ + + Process flow diagram illustrating the procedure for generating the OAE + Efficiency Map. We used a global ocean biogeochemical model to simulate the + effects of alkalinity surface forcing applied within different regions and + all four seasons. The difference between the baseline and injection + conditions simulated by the model enabled computing the net carbon removal + achieved by the OAE intervention and the associated efficiency (net carbon + uptake by the ocean per unit of alkalinity added). + +
+ +The model we used represents the three-dimensional circulation of the ocean and includes a biogeochemical model called MARBL. Since the physical circulation model is coarse resolution, its representation of the ocean flow is not perfect — but it does simulate broadly realistic circulation patterns, including surface currents, ocean overturning, and vertical mixing. MARBL provides a representation of the carbonate chemistry processes described above, as well as a representation of the lower trophic levels of the marine ecosystem. The air-sea CO₂ exchange rate is parameterized as a function of the square of the wind speed. This is a generally accepted parameterization, but it's important to note that it is an approximate relationship developed empirically. It is likely that coastal regions, for example, have a different wind speed dependence than the open ocean, due to additional constituents dissolved in the water and shorter distance of open water. + +To compute net CO₂ uptake induced by OAE, we evaluated the time evolution of the simulated air-sea CO₂ flux relative to baseline simulation that did not include the OAE intervention, but was otherwise identical. The importance of this counterfactual is illustrated by the fact that OAE can drive ocean carbon uptake even in regions characterized by outgassing (see Figure 1): an OAE-induced reduction in ocean outgassing is functionally equivalent to net carbon dioxide removal. To represent the counterfactual, we used MARBL’s ability to simultaneously simulate two seawater carbonate systems. We applied the alkalinity addition to the first carbonate system; then we used a difference between the fields simulated by the perturbed and unperturbed carbonate systems to compute OAE effects. + +You can learn more about our modeling approach in this [preprint](https://doi.org/10.21203/rs.3.rs-4124909/v1), and you can access the data via this [Source Cooperative repository](https://beta.source.coop/repositories/cworthy/oae-efficiency-atlas/description/). + +## Exploring the OAE Efficiency Tool + +We created an [interactive online tool](/research/oae-efficiency) to enable broader access to the OAE efficiency dataset. You can use this tool to build intuition about global patterns in OAE efficiency, and to explore how releasing alkalinity in a particular region and season leads to carbon removal over time. + +Figure 6 summarizes the OAE efficiency for all the global polygons.Keep in mind that the efficiency shown is a result of a full three-dimensional simulation of ocean circulation and biogeochemistry: alkalinity is added at each polygon, the model simulates the transport of the alkalinity away from that region, as well as changes in the carbonate system and the air-sea flux over that expanding plume. We then map the simulated efficiency back to the polygon of origin — but the carbon uptake does not exclusively occur within the polygon. You can choose the season of simulated alkalinity release, and use the slider to see how geographic patterns of OAE efficiency change through time. For example, the tool shows that a few regions stand out as having relatively high carbon removal over the course of a year or two post-alkalinity release. This includes subpolar regions in the North Atlantic, North Pacific, and Southern Ocean, as well as areas along the equator. As time progresses past the first couple of years, the amount of geographic variation in OAE efficiency begins to diminish. By year 15, much of the ocean begins to approach the thermodynamic maximum efficiency. An exception is the subtropical gyres and high-latitude regions, which even after 15 years have relatively low OAE efficiency. + +
+ + + Global variation in OAE efficiency as a function of time following + alkalinity release in different seasons. The colors show the OAE efficiency, + which is defined as the amount of carbon uptake in moles divided by the + number of moles of alkalinity added to the ocean. + +
+ +The tool also shows that the season of release has a modest effect on OAE efficiency. A dramatic exception, however, is seen in high latitude regions. In areas around Antarctica and the North Atlantic, releasing alkalinity in winter generates very little CO₂ uptake. This is because deep vertical mixing removes the alkalinity from the surface before air-sea CO₂ equilibration can occur. Notably, the loss of alkalinity from the surface ocean is essentially irreversible on timescales of a few decades, as much of the water that sinks in these regions will be entrained in the deep overturning circulation and will not return to the surface for decades, or even centuries. + +In addition to exploring patterns at a global scale, the interactive tool can also zoom into the regional level. In the map, you can click on any polygon to visualize how alkalinity released in that region disperses into a plume over time, and examine the associated evolution of carbon uptake and pH. As shown in Figure 7, releasing alkalinity in some regions leads to rapid CO₂ uptake, while others achieve carbon removal more slowly or are curtailed by physical ocean dynamics from the outset. + +
+ + + Regional OAE efficiency data for example polygons in the North Atlantic. The + map shows the polygon locations of alkalinity release. Click on a polygon + and use the elapsed time slider to see how alkalinity injection leads to + additional CO₂ uptake over space and time. The bottom right panel shows the + OAE efficiency curves — moles of carbon uptake per mole of alkalinity added + — over the 15-year model integrations. + +
+ +One pattern that stands out across regions is the large spatial scale over which CO₂ uptake occurs. For many regions, a significant portion of the total carbon uptake happens more than 1,000 kilometers away from the site of alkalinity addition. This emphasizes the importance of rigorous approaches to modeling to understand how OAE plays out over spatial and temporal scales that are difficult to observe directly. + +## How to use the OAE efficiency data + +There are different ways to start using the OAE efficiency dataset, depending on your interests. Here are some examples: + +
+ + Visit our map tool{' '} + where you can explore the data directly in your web browser, through both maps and time series data. + , + ], + [ + 'OAE researcher', + 'I want to perform additional in-depth analysis of the data.', + + Read the scientific paper and access the research-grade data{' '} +here. + , + ], + [ + 'CDR project', + 'I want to use these resources to make estimates of carbon removal from OAE deployments.', + + See our example calculation showing how, conceptually, these modeled results can be used to develop carbon removal estimates from arbitrary alkalinity releases. + , + ], + ]} + +/> + + + +We expect the use case of quantifying carbon removal from real-world OAE deployments to be of particular interest, but potential users should know that there are some limitations involved.The data and statistical approaches described here could also be relevant for direct ocean removal (DOR). DOR creates a CO₂ deficit by removing carbon directly from the surface ocean and, like OAE, removes carbon from the atmosphere via air-sea gas exchange. To apply the OAE efficiency data to DOR, it would be necessary to apply a chemistry-based conversion factor between alkalinity addition and dissolved inorganic carbon removal. + +First, the results are based on a single, coarse-resolution model. While we expect that the broad patterns of OAE efficiency would be similar if simulated in a different ocean model of comparable complexity, regional differences will certainly emerge due to differences in simulated flow and biogeochemical background state. The magnitude and sign of this effect will vary regionally. The spatial resolution of the model determines the scale of features in the ocean flow that can be represented explicitly. The model we used has a horizontal resolution of about 100 km, which is a fairly standard resolution for models used for climate projections. However, there are important features of the ocean flow that cannot be resolved at this scale. Improving the resolution of the model is likely to change the simulated OAE efficiency — but the magnitude, and even the sign of this effect, is also likely to vary regionally. + +Second, we only released alkalinity during a single year (1999). The model was run for 15-year simulations using historical data starting in 1999.The choice of the year 1999 was arbitrary and based simply on the desire to be able to integrate the model for a couple of decades following alkalinity release using historical meteorological data. As the experimental design was refined, we decided to run the model for only 15 years. As a result, the OAE Efficiency Map does not provide an indication of the variations in efficiency that would result from the interannual changes in atmospheric and oceanic conditions that would be sampled by different release years. Preliminary analysis demonstrates that there is an imprint of interannual variability on OAE efficiency, but the importance of this variability varies regionally. + +Third, we used a simplified alkalinity forcing. The model was forced at each polygon with a surface flux of total alkalinity, thus these data do not incorporate all the processes that could affect ultimate net carbon removal, including local-scale physics mediating initial dispersion patterns, the [dissolution](https://carbonplan.org/research/cdr-verification/docs/components/alk-total) of alkaline minerals, the potential for [mineral precipitation](https://carbonplan.org/research/cdr-verification/docs/components/sec-precip), or potential feedbacks on the natural alkalinity cycle. + +Finally, the model assumes an infinite atmospheric CO₂ reservoir. As OAE removes carbon from the atmosphere, the mole fraction of CO₂ in the atmosphere will decline. Our simulations do not include this effect, but rather assume that the atmospheric CO₂ is unaffected by the OAE deployment. The amount of CO₂ transferred to restore equilibrium will be less with a responsive atmospheric CO₂ reservoir. However, all CDR technologies, including direct air capture (DAC), will impact the atmospheric CO₂ and generate feedback through the rest of the global carbon cycle ([see this article](https://carbonplan.org/research/cdr-timescale-accounting) for a related discussion). Forcing the model as we have done is the best way to ensure comparability across carbon removal assessments for different CDR pathways, but accounting for the OAE effects on ocean carbon inventories and related properties (e.g., pH) will require a treatment with a responsive atmosphere. + +## The path forward + +We envision extending the OAE Efficiency Map to include treatment with higher resolution models over regional to basin-scale domains. Such datasets have a potentially important role to play in quantifying carbon removal, enabling effective site selection, helping people develop a deeper understanding of how OAE might affect ecosystems in space and time. Future work will also explore the role of interannual climate variability in driving changes in efficiency. We can imagine using historical variability and generating ensembles of OAE releases, for example, to provide meaningful estimates of the envelope of uncertainty in net carbon uptake stemming from this variability. + +We think these data have a big role to play in shaping the ongoing discussions about how to quantify and verify the effects of OAE and create reliable carbon removal standards. The dataset illustrates that carbon removal mediated by OAE is spread over large regions in space and occurs over multiple years. The fact that these models indicate that this removal is slow and widespread, rather than fast and localized, must shape the way we decide to set up accounting systems and market transactions around it. + + + + +Thanks to Lydia Kapsenberg of [CEA Consulting](https://www.ceaconsulting.com/) for helpful comments on drafts of this article. + + + + + +Matt, Mengyang, and Mike designed the numerical experiments. Mengyang performed the model simulations to generate the underlying data. Alicia conceived the idea to serve these data as a community dataset. Tom generated the dataset underlying the online tool and some of the explainer figures. Matt, Alicia, Freya, Kata, and Shane designed the figures; Kata and Shane produced the figures. Elizabeth and Tom produced the IRF convolution example. Matt and Freya wrote the article. All authors contributed to revising the text. Header image (modified) by [Koen Emmers](https://unsplash.com/photos/water-drop-on-body-of-water-Da1Wv-XC43k) on [Unsplash](https://unsplash.com/). + +Please cite as: + +M. Long et al. (2024) “Mapping the efficiency of ocean alkalinity enhancement.” CarbonPlan [https://carbonplan.org/research/oae-efficiency-explainer](https://carbonplan.org/research/oae-efficiency-explainer) + + + + + +CarbonPlan and [C]Worthy received funding from the [Carbon to Sea Initiative](https://carbontosea.org) and the [Environmental Defense Fund](https://www.edf.org) to implement the interactive tool and write this explainer article. The article text and figures are made available under a [CC BY 4.0 International license](https://creativecommons.org/licenses/by/4.0/). + +This material is based on work by [C]Worthy and collaborators that was supported by the National Center for Atmospheric Research (NCAR), a major facility sponsored by the National Science Foundation (NSF) under Cooperative Agreement No. 1852977. Mengyang received support from the Advanced Study Program Graduate Visitor Program at the National Center for Atmospheric Research. The authors acknowledge high performance computing support from the [Cheyenne](https://doi.org/10.5065/D6RX99HX) supercomputer provided by [NCAR's Computational and Information Systems Laboratory](https://www.cisl.ucar.edu/), sponsored by the NSF. + + diff --git a/articles/oae-efficiency-explainer/references.json b/articles/oae-efficiency-explainer/references.json new file mode 100644 index 00000000..6a063032 --- /dev/null +++ b/articles/oae-efficiency-explainer/references.json @@ -0,0 +1,106 @@ +{ + "Krumhardt.2024": { + "authors": "Krumhardt et al.", + "year": 2024, + "title": "From nutrients to fish: Impacts of mesoscale processes in a global CESM-FEISTY eddying ocean model framework", + "journal": "(preprint)", + "editors": "", + "url": "https://doi.org/10.31223/X5FQ2F" + }, + "he.2023": { + "authors": "He and Tyka", + "year": 2023, + "title": "Limits and CO₂ equilibration of near-coast alkalinity enhancement", + "journal": "Biogeosciences", + "editors": "", + "url": "https://doi.org/10.5194/bg-20-27-2023" + }, + "friedlingstein.2023": { + "authors": "Friedlingstein et al.", + "year": 2023, + "title": "Global Carbon Budget 2023", + "journal": "Earth Syst. Sci. Data", + "editors": "", + "url": "https://doi.org/10.5194/essd-15-5301-2023" + }, + "doney.2009": { + "authors": "Doney et al.", + "year": 2009, + "title": "Ocean Acidification: The Other CO₂ Problem", + "journal": "Annual Review of Marine Science", + "editors": "", + "url": "https://doi.org/10.1146/annurev.marine.010908.163834" + }, + "long.2021": { + "authors": "Long et al.", + "year": 2021, + "title": "Simulations with the Marine Biogeochemistry Library (MARBL)", + "journal": "Journal of Advances in Modeling Earth Systems", + "editors": "", + "url": "https://doi.org/10.1029/2021MS002647" + }, + "sigman&hain.2012": { + "authors": "Sigman & Haine", + "year": 2012, + "title": "The Biological Productivity of the Ocean: Section 3", + "journal": "Nature Education Knowledge", + "editors": "", + "url": "https://www.nature.com/scitable/knowledge/library/the-biological-productivity-of-the-ocean-section-71072666/" + }, + "bach.2019": { + "authors": "Bach et al.", + "year": 2019, + "title": "CO₂ Removal With Enhanced Weathering and Ocean Alkalinity Enhancement: Potential Risks and Co-benefits for Marine Pelagic Ecosystems", + "journal": "Frontiers in Climate", + "editors": "", + "url": "https://doi.org/10.3389/fclim.2019.00007" + }, + "hinrichs.2023": { + "authors": "Hinrichs et al.", + "year": 2023, + "title": "Alkalinity biases in CMIP6 Earth system models and implications for simulated CO₂ drawdown via artificial alkalinity enhancement", + "journal": "Biogeosciences", + "editors": "", + "url": "https://doi.org/10.5194/bg-20-3717-2023" + }, + "wanninkhof.2014": { + "authors": "Wanninkhof", + "year": 2014, + "title": "Relationship between wind speed and gas exchange over the ocean revisited", + "journal": "Limnol. Oceanogr. Methods", + "editors": "", + "url": "https://doi.org/10.4319/lom.2014.12.351" + }, + "ho.2006": { + "authors": "Ho et al.", + "year": 2006, + "title": "Measurements of air-sea gas exchange at high wind speeds in the Southern Ocean: Implications for global parameterizations", + "journal": "Geophysical Research Letters", + "editors": "", + "url": "https://doi.org/10.1029/2006GL026817" + }, + "dobashi.2023": { + "authors": "Dobashi and Ho", + "year": 2023, + "title": "Air–sea gas exchange in a seagrass ecosystem – results from a ³He ∕ SF₆ tracer release experiment", + "journal": "Biogeosciences", + "editors": "", + "url": "https://doi.org/10.5194/bg-20-1075-2023" + }, + "moras.2022": { + "authors": "Moras et al.", + "year": 2022, + "title": "Ocean alkalinity enhancement – avoiding runaway CaCO₃ precipitation during quick and hydrated lime dissolution", + "journal": "Biogeosciences", + "editors": "", + "url": "https://doi.org/10.5194/bg-19-3537-2022" + }, + "bach.2024": { + "authors": "Bach", + "year": 2024, + "title": "The additionality problem of ocean alkalinity enhancement", + "journal": "Biogeosciences", + "editors": "", + "url": "https://doi.org/10.5194/bg-21-261-2024" + } +} diff --git a/components/mdx/page-components.js b/components/mdx/page-components.js index fa11fca1..e79d1152 100644 --- a/components/mdx/page-components.js +++ b/components/mdx/page-components.js @@ -3,6 +3,58 @@ import dynamic from 'next/dynamic' // NOTE: This is a dynamically generated file based on the config specified under the // `components` key in each article's frontmatter. const components = { + 'oae-efficiency-explainer': { + FluxMap: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/flux-map.js' + ).then((mod) => mod.FluxMap || mod.default) + ), + PhysicalProcesses: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/physical-processes.js' + ).then((mod) => mod.PhysicalProcesses || mod.default) + ), + ModelingMethods: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/modeling-methods.js' + ).then((mod) => mod.ModelingMethods || mod.default) + ), + EfficienciesMap: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/efficiencies-map.js' + ).then((mod) => mod.EfficienciesMap || mod.default) + ), + RegionalComparison: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/regional-comparison.js' + ).then((mod) => mod.RegionalComparison || mod.default) + ), + AlkChemDiagram: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/alk-chem-diagram.js' + ).then((mod) => mod.AlkChemDiagram || mod.default) + ), + CarbChemDiagram: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/carb-chem-diagram.js' + ).then((mod) => mod.CarbChemDiagram || mod.default) + ), + DataWrapper: dynamic(() => + import('../../articles/oae-efficiency-explainer/components/data.js').then( + (mod) => mod.DataWrapper || mod.default + ) + ), + HCO3: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/chemistry.js' + ).then((mod) => mod.HCO3 || mod.default) + ), + CO3: dynamic(() => + import( + '../../articles/oae-efficiency-explainer/components/chemistry.js' + ).then((mod) => mod.CO3 || mod.default) + ), + }, 'enhanced-weathering-fluxes': { ErwEstimates: dynamic(() => import( From 589f4f9ff512abc59d226184e5978efa8d556222 Mon Sep 17 00:00:00 2001 From: katamartin Date: Mon, 15 Jul 2024 15:36:44 -0400 Subject: [PATCH 11/11] Clean up unused component --- .../components/carbonate-slider.js | 173 ------------------ 1 file changed, 173 deletions(-) delete mode 100644 articles/oae-efficiency-explainer/components/carbonate-slider.js diff --git a/articles/oae-efficiency-explainer/components/carbonate-slider.js b/articles/oae-efficiency-explainer/components/carbonate-slider.js deleted file mode 100644 index 3346fc6a..00000000 --- a/articles/oae-efficiency-explainer/components/carbonate-slider.js +++ /dev/null @@ -1,173 +0,0 @@ -import React from 'react' -import { Box, Flex, Label, Checkbox, Slider } from 'theme-ui' - -const CarbonateSlider = ({ - data, - slidableVariable, - varIndex, - setVarIndex, - equilibrated, - setEquilibrated, -}) => { - return ( - - {data.dic && ( - <> - - - - {data.dic[varIndex] > 0 - ? `+${data.dic[varIndex].toFixed()}` - : data.dic[varIndex].toFixed()} - - - Ocean carbon (DIC) - - - - - {data.ph[varIndex] > 0 - ? `+${data.ph[varIndex].toFixed(2)}` - : data.ph[varIndex].toFixed(2)} - - - pH - - - - - - - {data.co2[varIndex] > 0 - ? `+${data.co2[varIndex].toFixed()}` - : data.co2[varIndex].toFixed()} - - - CO₂ - - - - - {data.hco3[varIndex] > 0 - ? `+${data.hco3[varIndex].toFixed()}` - : data.hco3[varIndex].toFixed()} - - - HCO₃ - - - - - {data.co3[varIndex] > 0 - ? `+${data.co3[varIndex].toFixed()}` - : data.co3[varIndex].toFixed()} - - - CO₃ - - - - - )} - - (∆µmol / kg seawater) - - - setVarIndex(parseFloat(e.target.value))} - min={0} - max={ - data && slidableVariable.key in data - ? Object.keys(data[slidableVariable.key]).length - 1 - : 0 - } - step={1} - /> - - - - + - {data[slidableVariable.key] && - data[slidableVariable.key][varIndex].toFixed(0)} - - {slidableVariable.name} - {equilibrated !== undefined && ( - - )} - - - ) -} - -export default CarbonateSlider