-
Notifications
You must be signed in to change notification settings - Fork 10
Fluxy #89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
lionel42
wants to merge
23
commits into
master
Choose a base branch
from
fluxy
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Fluxy #89
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
24bf5d8
fix edgar missing vars reuqired
lionel42 a2ec3d9
adding first draft of fluxy export
lionel42 a52868e
first draft of example
lionel42 09c54cc
adding tests
lionel42 62408c4
fixes from the tests
lionel42 5f53852
adding doc
lionel42 e0f5991
cleaned test header
lionel42 01f1bab
Update scripts/exports/edgar_2_fluxy.ipynb
lionel42 f988ce1
fix false typo
lionel42 ae39058
fixed import and annotations
lionel42 a4a5919
Merge branch 'fluxy' of github.com:C2SM-RCM/emiproc into fluxy
lionel42 6e5d5a5
Merge branch 'master' of github.com:C2SM-RCM/emiproc into fluxy
lionel42 0fd330b
fix typo
lionel42 999baaa
removed useless variables
lionel42 1bc58f1
year -> yr
lionel42 15a0251
convert to correct area units
lionel42 066a3d3
formatting and consistency
lionel42 49fda89
remove uncertainty variables
lionel42 c2d2559
removed percentile ctd
lionel42 0aa0299
remove warning about _
lionel42 dab4670
Update scripts/exports/edgar_2_fluxy.ipynb
lionel42 0334f8a
fix test
lionel42 6123b51
Merge branch 'fluxy' of github.com:C2SM-RCM/emiproc into fluxy
lionel42 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
from __future__ import annotations | ||
|
||
import logging | ||
from os import PathLike | ||
from pathlib import Path | ||
|
||
import numpy as np | ||
import xarray as xr | ||
from pyproj import CRS | ||
|
||
from emiproc.exports.utils import get_temporally_scaled_array | ||
from emiproc.grids import RegularGrid | ||
from emiproc.inventories import Inventory | ||
from emiproc.utilities import get_country_mask | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def export_fluxy( | ||
invs: Inventory | list[Inventory], | ||
output_dir: PathLike, | ||
transport_model: str = "emiproc", | ||
frequency: str = "yearly", | ||
) -> None: | ||
"""Export emissions to Fluxy format. | ||
|
||
https://github.com/openghg/fluxy | ||
|
||
Fluxy is a python plotting tool for comparing inverse modeling results. | ||
As part of fluxy, it is possible to plot prior emissions. | ||
|
||
The following is required on inventories to be exported to fluxy: | ||
|
||
* The inventory must have a :py:class:`~emiproc.grids.RegularGrid`. | ||
* The inventory must have a year value given. (not None). | ||
* The inventory must have temporal profiles. . | ||
|
||
Fluxy files must have a specifc format. | ||
The files are generated in the following way: | ||
|
||
* <transport_model>_<substance>_<frequency>.nc | ||
|
||
|
||
:param invs: Inventory or list of inventories to export. | ||
A list of inventory assumes that you want to plot the emissions over multiple years. | ||
:param output_dir: Directory to export the emissions to. | ||
This directory is the name of the transport model in fluxy. | ||
:param transport_model: The transport model name to "fake". (default: `emiproc`) | ||
|
||
:return: None | ||
|
||
|
||
""" | ||
|
||
output_dir = Path(output_dir) / transport_model | ||
output_dir.mkdir(parents=True, exist_ok=True) | ||
|
||
if isinstance(invs, Inventory): | ||
invs = [invs] | ||
if not isinstance(invs, list): | ||
raise TypeError(f"Expected Inventory or list of Inventory, got {type(invs)}.") | ||
if len(invs) == 0: | ||
raise ValueError("Expected at least one inventory.") | ||
|
||
# Check that the grids are all the same | ||
grids = [inv.grid for inv in invs] | ||
if len(set(grids)) != 1: | ||
raise ValueError( | ||
"All inventories must have the same grid. " | ||
f"Got {[grid.name for grid in grids]}." | ||
) | ||
grid = grids[0] | ||
assert isinstance(grid, RegularGrid), "Only regular grids are supported." | ||
|
||
# Check the grid is on WGS84 | ||
if not CRS(grid.crs) == CRS("WGS84"): | ||
raise ValueError("The grid must be on WGS84. " f"Got {grid.crs}.") | ||
|
||
def cell_to_lat_lon(ds: xr.Dataset): | ||
ds = ds.assign_coords( | ||
latitude=("cell", np.tile(grid.lat_range, grid.nx)), | ||
longitude=("cell", np.repeat(grid.lon_range, grid.ny)), | ||
) | ||
# Set the stacked coordinate as a multi-index | ||
ds = ds.set_index(cell=["latitude", "longitude"]) | ||
ds = ds.unstack({"cell": ("latitude", "longitude")}) | ||
return ds | ||
|
||
da_fractions = get_country_mask(grid, return_fractions=True) | ||
da_fractions = cell_to_lat_lon(da_fractions) | ||
|
||
substances = set(sum((inv.substances for inv in invs), [])) | ||
|
||
# First create a template with the grid and the time dimension | ||
ds_template = xr.Dataset( | ||
coords={ | ||
"longitude": ( | ||
"longitude", | ||
grid.lon_range, | ||
{ | ||
"standard_name": "longitude", | ||
"long_name": "longitude of grid cell centre", | ||
"units": "degrees_east", | ||
"axis": "X", | ||
}, | ||
), | ||
"latitude": ( | ||
"latitude", | ||
grid.lat_range, | ||
{ | ||
"standard_name": "latitude", | ||
"long_name": "latitude of grid cell centre", | ||
"units": "degrees_north", | ||
"axis": "Y", | ||
}, | ||
), | ||
"country": ( | ||
"country", | ||
da_fractions["country"].data, | ||
), | ||
}, | ||
data_vars={ | ||
"country_fraction": ( | ||
("country", "latitude", "longitude"), | ||
da_fractions.data, | ||
{ | ||
"long_name": "fraction of grid cell associated to country", | ||
"units": "1", | ||
"comments": "calculated by emiproc", | ||
}, | ||
), | ||
}, | ||
) | ||
|
||
# Check that all inventories have year not equal to None | ||
invs_years = [inv.year for inv in invs] | ||
if None in invs_years: | ||
raise ValueError("All inventories must have a year. " f"Got {invs_years=}.") | ||
# Make sure the years are all different | ||
if len(set(invs_years)) != len(invs_years): | ||
raise ValueError( | ||
"All inventories must have different years. " f"Got {invs_years=}." | ||
) | ||
|
||
dss = [ | ||
get_temporally_scaled_array( | ||
inv, | ||
time_range=inv.year, | ||
sum_over_cells=False, | ||
) | ||
for inv in invs | ||
] | ||
|
||
# Put all together and sum over the categories to have total emissions | ||
ds = xr.concat(dss, dim="time").sum(dim="category") | ||
|
||
# Convert to fluxes (kg yr-1 -> kg m-2 yr-1) | ||
ds /= xr.DataArray(grid.cell_areas, coords={"cell": ds["cell"]}) | ||
|
||
ds = cell_to_lat_lon(ds) | ||
|
||
units = {"units": "kg m-2 yr-1"} | ||
|
||
for sub in substances: | ||
sub_dir = output_dir / sub | ||
sub_dir.mkdir(parents=True, exist_ok=True) | ||
file_stem = "_".join( | ||
[ | ||
transport_model, | ||
sub, | ||
frequency, | ||
] | ||
) | ||
da_this = ds.sel(substance=sub).drop_vars("substance").assign_attrs(units) | ||
ds_this = ds_template.assign(flux_total_prior=da_this) | ||
# Calculate the country flux | ||
ds_this = ds_this.assign( | ||
country_flux_total_prior=( | ||
ds_this["flux_total_prior"] * ds_this["country_fraction"] | ||
) | ||
.sum(dim=["latitude", "longitude"]) | ||
.assign_attrs(units), | ||
) | ||
|
||
ds_this = ds_this.assign( | ||
**{ | ||
# Assign the same variable names as the prior for the posterior variables | ||
var_prior.replace("prior", "posterior"): ds_this[var_prior] | ||
for var_prior in [ | ||
"flux_total_prior", | ||
"country_flux_total_prior", | ||
] | ||
} | ||
) | ||
|
||
ds_this.to_netcdf( | ||
sub_dir / f"{file_stem}.nc", | ||
) | ||
|
||
logger.info(f"Exported {len(substances)} substances to {output_dir}.") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.