test_conversion.py 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. import climate_categories as cc
  2. import primap2 as pm2
  3. import xarray as xr
  4. from src.faostat_data_primap.helper.category_aggregation import (
  5. agg_info_fao,
  6. agg_info_ipcc2006_primap,
  7. )
  8. from src.faostat_data_primap.helper.paths import (
  9. downloaded_data_path,
  10. extracted_data_path,
  11. )
  12. from src.faostat_data_primap.read import read_data
  13. def test_conversion_from_FAO_to_IPCC2006_PRIMAP():
  14. # make categorisation A from yaml
  15. categorisation_a = cc.from_python("FAO.py")
  16. # make categorisation B from yaml
  17. categorisation_b = cc.IPCC2006_PRIMAP
  18. # category FAOSTAT not yet part of climate categories, so we need to add it manually
  19. cats = {
  20. "FAOSTAT": categorisation_a,
  21. "IPCC2006_PRIMAP": categorisation_b,
  22. }
  23. ds_fao = (
  24. extracted_data_path
  25. / "v2024-11-14/FAOSTAT_Agrifood_system_emissions_v2024-11-14_raw.nc"
  26. )
  27. ds = pm2.open_dataset(ds_fao)
  28. # consistency check in original categorisation
  29. # drop UNFCCC data
  30. ds = ds.drop_sel(source="UNFCCC")
  31. #
  32. # # Checking consistency of category tree in FAO categorisation
  33. # # There are discrepancies of up to 100% due to rounding errors for small values
  34. # # theoretical example, 0.0001 (rounded from 0.00006) + 0.0004 (rounded from 0.00036)
  35. # # = 0.00042 which is then rounded to 0.0004, while the consistency check expects 0.0005
  36. # # At the moment, we are only checking categories that will later be used by primap-hist.
  37. # # If we want to use other categories we should expand this consistency check.
  38. # agg_info_fao = {
  39. # "category (FAOSTAT)": {
  40. # # 1.A.1 wheat
  41. # # rounding errors
  42. # "1.A.1.a": {
  43. # "tolerance": 1,
  44. # "sources": [
  45. # "1.A.1.a.i",
  46. # "1.A.1.a.ii",
  47. # ],
  48. # "sel": {"variable": ["N2O"]},
  49. # },
  50. # "1.A.1": {
  51. # "tolerance": 0.01,
  52. # "sources": [
  53. # "1.A.1.a",
  54. # "1.A.1.b",
  55. # ],
  56. # "sel": {"variable": ["N2O", "CH4"]},
  57. # },
  58. # # 1.A.2 rice
  59. # # rounding errors
  60. # "1.A.2.a": {
  61. # "tolerance": 1,
  62. # "sources": [
  63. # "1.A.2.a.i",
  64. # "1.A.2.a.ii",
  65. # ],
  66. # "sel": {"variable": ["N2O"]},
  67. # },
  68. # "1.A.2": {
  69. # "tolerance": 0.01,
  70. # "sources": [
  71. # "1.A.2.a",
  72. # "1.A.2.b",
  73. # "1.A.2.c", # rice cultivation CH4
  74. # ],
  75. # "sel": {"variable": ["N2O", "CH4"]},
  76. # },
  77. # # potatoes
  78. # "1.A.3.a": {
  79. # "tolerance": 1,
  80. # "sources": [
  81. # "1.A.3.a.i",
  82. # "1.A.3.a.ii",
  83. # ],
  84. # "sel": {"variable": ["N2O"]},
  85. # },
  86. # "1.A.3": {
  87. # "tolerance": 0.01,
  88. # "sources": [
  89. # "1.A.3.a",
  90. # ],
  91. # "sel": {"variable": ["N2O"]},
  92. # },
  93. # # millet
  94. # "1.A.4.a": {
  95. # "tolerance": 1,
  96. # "sources": [
  97. # "1.A.4.a.i",
  98. # "1.A.4.a.ii",
  99. # ],
  100. # "sel": {"variable": ["N2O"]},
  101. # },
  102. # "1.A.4": {
  103. # "tolerance": 0.01,
  104. # "sources": [
  105. # "1.A.4.a",
  106. # ],
  107. # "sel": {"variable": ["N2O"]},
  108. # },
  109. # # barley
  110. # "1.A.5.a": {
  111. # "tolerance": 1,
  112. # "sources": [
  113. # "1.A.5.a.i",
  114. # "1.A.5.a.ii",
  115. # ],
  116. # "sel": {"variable": ["N2O"]},
  117. # },
  118. # "1.A.5": {
  119. # "tolerance": 0.01,
  120. # "sources": [
  121. # "1.A.5.a",
  122. # ],
  123. # "sel": {"variable": ["N2O"]},
  124. # },
  125. # # barley
  126. # "1.A.6.a": {
  127. # "tolerance": 1,
  128. # "sources": [
  129. # "1.A.6.a.i",
  130. # "1.A.6.a.ii",
  131. # ],
  132. # "sel": {"variable": ["N2O"]},
  133. # },
  134. # "1.A.6": {
  135. # "tolerance": 0.01,
  136. # "sources": [
  137. # "1.A.6.a",
  138. # "1.A.6.b",
  139. # ],
  140. # "sel": {"variable": ["N2O", "CH4"]},
  141. # },
  142. # # sugar cane
  143. # "1.A.7.a": {
  144. # "tolerance": 1,
  145. # "sources": [
  146. # "1.A.7.a.i",
  147. # "1.A.7.a.ii",
  148. # ],
  149. # "sel": {"variable": ["N2O"]},
  150. # },
  151. # "1.A.7": {
  152. # "tolerance": 0.01,
  153. # "sources": [
  154. # "1.A.7.a",
  155. # "1.A.7.b",
  156. # ],
  157. # "sel": {"variable": ["N2O", "CH4"]},
  158. # },
  159. # # dry beans
  160. # "1.A.8.a": {
  161. # "tolerance": 1,
  162. # "sources": [
  163. # "1.A.8.a.i",
  164. # "1.A.8.a.ii",
  165. # ],
  166. # "sel": {"variable": ["N2O"]},
  167. # },
  168. # "1.A.8": {
  169. # "tolerance": 0.01,
  170. # "sources": [
  171. # "1.A.8.a",
  172. # ],
  173. # "sel": {"variable": ["N2O"]},
  174. # },
  175. # # oats
  176. # "1.A.9.a": {
  177. # "tolerance": 1,
  178. # "sources": [
  179. # "1.A.9.a.i",
  180. # "1.A.9.a.ii",
  181. # ],
  182. # "sel": {"variable": ["N2O"]},
  183. # },
  184. # "1.A.9": {
  185. # "tolerance": 0.01,
  186. # "sources": [
  187. # "1.A.9.a",
  188. # ],
  189. # "sel": {"variable": ["N2O"]},
  190. # },
  191. # # rye
  192. # "1.A.10.a": {
  193. # "tolerance": 1,
  194. # "sources": [
  195. # "1.A.10.a.i",
  196. # "1.A.10.a.ii",
  197. # ],
  198. # "sel": {"variable": ["N2O"]},
  199. # },
  200. # "1.A.10": {
  201. # "tolerance": 0.01,
  202. # "sources": [
  203. # "1.A.10.a",
  204. # ],
  205. # "sel": {"variable": ["N2O"]},
  206. # },
  207. # # sorghum
  208. # "1.A.11.a": {
  209. # "tolerance": 1,
  210. # "sources": [
  211. # "1.A.11.a.i",
  212. # "1.A.11.a.ii",
  213. # ],
  214. # "sel": {"variable": ["N2O"]},
  215. # },
  216. # "1.A.11": {
  217. # "tolerance": 0.01,
  218. # "sources": [
  219. # "1.A.11.a",
  220. # ],
  221. # "sel": {"variable": ["N2O"]},
  222. # },
  223. # # soya beans
  224. # "1.A.12.a": {
  225. # "tolerance": 1,
  226. # "sources": [
  227. # "1.A.12.a.i",
  228. # "1.A.12.a.ii",
  229. # ],
  230. # "sel": {"variable": ["N2O"]},
  231. # },
  232. # "1.A.12": {
  233. # "tolerance": 0.01,
  234. # "sources": [
  235. # "1.A.12.a",
  236. # ],
  237. # "sel": {"variable": ["N2O"]},
  238. # },
  239. # "1.A": {
  240. # # some rounding errors for CH4
  241. # "tolerance": 1,
  242. # "sources": [
  243. # "1.A.1",
  244. # "1.A.2",
  245. # "1.A.3",
  246. # "1.A.4",
  247. # "1.A.5",
  248. # "1.A.6",
  249. # "1.A.7",
  250. # "1.A.8",
  251. # "1.A.9",
  252. # "1.A.10",
  253. # "1.A.11",
  254. # "1.A.12",
  255. # ],
  256. # },
  257. # "1.B.2": {
  258. # "tolerance": 0.01,
  259. # "sources": [
  260. # "1.B.2.a",
  261. # "1.B.2.b",
  262. # ],
  263. # "sel": {"variable": ["N2O"]},
  264. # },
  265. # "1.B": {
  266. # "tolerance": 1,
  267. # "sources": [
  268. # "1.B.1",
  269. # "1.B.2",
  270. # ],
  271. # "sel": {"variable": ["N2O"]},
  272. # },
  273. # # Category 1 is not available on FAOSTAT, so that's not a check
  274. # "1": {
  275. # "tolerance": 0.01,
  276. # "sources": [
  277. # "1.A",
  278. # "1.B",
  279. # ],
  280. # },
  281. # "3": {
  282. # # mostly rounding errors, Macedonia slightly higher than 100% discrepancy
  283. # # Saint Pierre and Miquelon, 1992, N20 200% error, considered negligible
  284. # "tolerance": 2.01,
  285. # "sources": [
  286. # "3.A",
  287. # "3.B",
  288. # "3.C",
  289. # "3.D",
  290. # "3.E",
  291. # "3.F",
  292. # "3.G",
  293. # "3.H",
  294. # "3.I",
  295. # "3.J",
  296. # "3.K",
  297. # "3.L",
  298. # # "3.M", # poultry is an aggregate of other categories I forgot to remove
  299. # "3.N",
  300. # "3.O",
  301. # "3.P",
  302. # "3.Q",
  303. # "3.R",
  304. # ],
  305. # "sel": {"variable": ["CH4", "N2O"]},
  306. # },
  307. # # Testing for one animal type to make sure the category tree makes sense
  308. # # TODO: We could do the same for each animal but that's a lot of effort
  309. # "3.C.3.b" : {
  310. # "tolerance": 1,
  311. # "sources": [
  312. # "3.C.3.b.i",
  313. # "3.C.3.b.ii",
  314. # ],
  315. # "sel": {"variable": ["N2O"]},
  316. # },
  317. # "3.C.3" : {
  318. # "tolerance" : 1,
  319. # "sources" : [
  320. # "3.C.3.a",
  321. # "3.C.3.b",
  322. # ],
  323. # "sel" : {"variable" : ["N2O"]},
  324. # },
  325. # "3.C.2.b" : {
  326. # "tolerance" : 1,
  327. # "sources" : [
  328. # "3.C.2.b.i",
  329. # "3.C.2.b.ii",
  330. # ],
  331. # "sel" : {"variable" : ["N2O"]},
  332. # },
  333. # "3.C.2" : {
  334. # "tolerance" : 1,
  335. # "sources" : [
  336. # "3.C.2.a",
  337. # "3.C.2.b",
  338. # ],
  339. # "sel" : {"variable" : ["N2O"]},
  340. # },
  341. # "3.C.1" : {
  342. # "tolerance" : 1,
  343. # "sources" : [
  344. # "3.C.1.a",
  345. # "3.C.1.b",
  346. # "3.C.1.c",
  347. # ],
  348. # "sel" : {"variable" : ["N2O", "CH4"]},
  349. # },
  350. # "3.C" : {
  351. # "tolerance" : 1,
  352. # "sources" : [
  353. # "3.C.1",
  354. # "3.C.2",
  355. # "3.C.3",
  356. # "3.C.4",
  357. # ],
  358. # "sel" : {"variable" : ["N2O", "CH4"]},
  359. # },
  360. # "4": {
  361. # "tolerance": 0.01,
  362. # "sources": [
  363. # "4.A",
  364. # "4.B",
  365. # ],
  366. # "sel": {"variable": ["CO2"]},
  367. # },
  368. # "5" : {
  369. # "tolerance" : 0.2,
  370. # "sources" : [
  371. # "5.A",
  372. # "5.B",
  373. # ],
  374. # "sel" : {"variable" : ["CO2", "N2O"]},
  375. # },
  376. # "6.A" : {
  377. # "tolerance" : 1,
  378. # "sources" : [
  379. # "6.A.1",
  380. # "6.A.2",
  381. # ],
  382. # "sel" : {"variable" : ["CH4", "N2O", "CO2"]},
  383. # },
  384. # "6.B": {
  385. # # rounding errors, NLD looks problematic but hard to tell which value is right
  386. # "tolerance": 1,
  387. # "sources": [
  388. # "6.B.1",
  389. # "6.B.2",
  390. # "6.B.3",
  391. # "6.B.4",
  392. # "6.B.5",
  393. # ],
  394. # "sel": {"variable": ["CH4", "N2O", "CO2"]},
  395. # },
  396. # "6" : {
  397. # "tolerance" : 0.01,
  398. # "sources" : [
  399. # "6.A",
  400. # "6.B",
  401. # "6.C",
  402. # ],
  403. # "sel" : {"variable" : ["CH4", "N2O", "CO2"]},
  404. # },
  405. # }
  406. # }
  407. ds_checked = ds.pr.add_aggregates_coordinates(agg_info=agg_info_fao) # noqa: F841
  408. # ds_checked_if = ds_checked.pr.to_interchange_format()
  409. # We need a comversion CSV file for each entity
  410. # That's a temporary workaround until convert function can filter for data variables (entities)
  411. conv = {}
  412. gases = ["CO2", "CH4", "N2O"]
  413. for var in gases:
  414. conv[var] = cc.Conversion.from_csv(
  415. f"../../conversion_FAO_IPPCC2006_PRIMAP_{var}.csv", cats=cats
  416. )
  417. # convert for each entity
  418. da_dict = {}
  419. for var in gases:
  420. da_dict[var] = ds[var].pr.convert(
  421. dim="category (FAOSTAT)",
  422. conversion=conv[var],
  423. )
  424. result = xr.Dataset(da_dict)
  425. result.attrs = ds.attrs
  426. result.attrs["cat"] = "category (IPCC2006_PRIMAP)"
  427. # convert to interchange format and back to get rid of empty categories
  428. result_if = result.pr.to_interchange_format()
  429. result = pm2.pm2io.from_interchange_format(result_if)
  430. # agg_info_ipcc2006_primap = {
  431. # "category (IPCC2006_PRIMAP)": {
  432. # "3.C.1": {
  433. # "sources": ["3.C.1.a", "3.C.1.b", "3.C.1.c"],
  434. # },
  435. # "M.3.C.AG": {
  436. # "sources": [
  437. # "3.C.1.b", # Biomass Burning In Croplands
  438. # "3.C.1.c", # Biomass Burning in Grasslands
  439. # "3.C.4", # Direct N2O Emissions from Managed Soils
  440. # "3.C.5", # Indirect N2O Emissions from Managed Soils
  441. # "3.C.6", # Indirect N2O Emissions from Manure Management
  442. # ],
  443. # },
  444. # "M.AG.ELV": {
  445. # "sources": ["M.3.C.AG"], # "M.3.D.AG" is zero
  446. # },
  447. # "3.C": {
  448. # "sources": [
  449. # "3.C.1",
  450. # "3.C.2",
  451. # "3.C.3",
  452. # "3.C.4",
  453. # "3.C.5",
  454. # "3.C.6",
  455. # "3.C.7",
  456. # ]
  457. # },
  458. # # "3.D" : {"sources" : ["3.D.1", "3.D.2"]}, # we don't have it
  459. # "3.A.1.a": { # cattle (dairy) + cattle (non-dairy)
  460. # "sources": [
  461. # "3.A.1.a.i",
  462. # "3.A.1.a.ii",
  463. # ]
  464. # },
  465. # "3.A.1": {
  466. # "sources": [
  467. # "3.A.1.a",
  468. # "3.A.1.b",
  469. # "3.A.1.c",
  470. # "3.A.1.d",
  471. # "3.A.1.e",
  472. # "3.A.1.f",
  473. # "3.A.1.g",
  474. # "3.A.1.h", # 3.A.1.i poultry left out because it is a group of categories
  475. # "3.A.1.j",
  476. # ]
  477. # },
  478. # "3.A.2.a": { # decomposition of manure cattle (dairy) + cattle (non-dairy)
  479. # "sources": [
  480. # "3.A.2.a.i",
  481. # "3.A.2.a.ii",
  482. # ]
  483. # },
  484. # "3.A.2": {
  485. # "sources": [
  486. # "3.A.2.a",
  487. # "3.A.2.b",
  488. # "3.A.2.c",
  489. # "3.A.2.d",
  490. # "3.A.2.e",
  491. # "3.A.2.f",
  492. # "3.A.2.g",
  493. # "3.A.2.h",
  494. # "3.A.2.i",
  495. # "3.A.2.j",
  496. # ]
  497. # },
  498. # "3.A": {"sources": ["3.A.1", "3.A.2"]},
  499. # "M.AG": {"sources": ["3.A", "M.AG.ELV"]},
  500. # # "M.3.D.LU": {"sources": ["3.D.1"]},
  501. # # For LULUCF Forest Land, Cropland, Grassland, is all we have
  502. # "M.LULUCF": {
  503. # "sources": [
  504. # "3.B.1", # Carbon stock change in forests
  505. # "3.B.2", # Drained grassland
  506. # "3.B.3", # Drained cropland
  507. # "3.C.1.a", # Biomass Burning In Forests
  508. # ]
  509. # }, # forest fires
  510. # "3": {"sources": ["M.AG", "M.LULUCF"]},
  511. # }
  512. # }
  513. result_proc = result.pr.add_aggregates_coordinates(
  514. agg_info=agg_info_ipcc2006_primap
  515. )
  516. result_proc_if = result_proc.pr.to_interchange_format()
  517. # save processed data
  518. release_name = "v2024-11-14"
  519. output_filename = f"FAOSTAT_Agrifood_system_emissions_{release_name}"
  520. output_folder = extracted_data_path / release_name
  521. if not output_folder.exists():
  522. output_folder.mkdir()
  523. filepath = output_folder / (output_filename + ".csv")
  524. print(f"Writing processed primap2 file to {filepath}")
  525. pm2.pm2io.write_interchange_format(
  526. filepath,
  527. result_proc_if,
  528. )
  529. compression = dict(zlib=True, complevel=9)
  530. encoding = {var: compression for var in result_proc.data_vars}
  531. filepath = output_folder / (output_filename + ".nc")
  532. print(f"Writing netcdf file to {filepath}")
  533. result_proc.pr.to_netcdf(filepath, encoding=encoding)
  534. def test_read(tmp_path):
  535. domains_and_releases_to_read = [
  536. # ("farm_gate_agriculture_energy", "2024-11-14"),
  537. # ("farm_gate_emissions_crops", "2024-11-14"),
  538. # ("farm_gate_livestock", "2024-11-14"),
  539. # ("land_use_drained_organic_soils", "2024-11-14"),
  540. ("land_use_fires", "2023-11-09"),
  541. # ("land_use_forests", "2024-11-14"),
  542. # ("pre_post_agricultural_production", "2024-11-14"),
  543. ]
  544. read_data(
  545. domains_and_releases_to_read=domains_and_releases_to_read,
  546. read_path=downloaded_data_path,
  547. save_path=tmp_path,
  548. )
  549. def test_yaml_to_python():
  550. cat = cc.from_yaml("FAO.yaml")
  551. cat.to_python("FAO.py")
  552. def test_python_to_yaml():
  553. from FAO import spec
  554. cat = cc.from_spec(spec)
  555. assert cat
  556. def test_make_dict_comprehension_for_faster_typing(): # noqa: PLR0912 PLR0915
  557. spec = {
  558. "name": "FAOSTAT",
  559. "title": (
  560. "Food and Agriculture Organization of the United Nations (FAO) "
  561. "FAOSTAT data set categorisation"
  562. ),
  563. "comment": "Needed to add FAOSTAT data to PRIMAP-hist",
  564. "references": "",
  565. "institution": "FAO",
  566. "hierarchical": True,
  567. "last_update": "2024-12-10",
  568. "version": "2024",
  569. "total_sum": True,
  570. "canonical_top_level_category": "0",
  571. }
  572. categories = {}
  573. # 0. main categories
  574. categories["0"] = {
  575. "title": "Total",
  576. "comment": "All emissions and removals",
  577. "children": [["1", "2", "3", "4", "5", "6", "7"]],
  578. }
  579. children_1 = ["1.A", "1.B"]
  580. children_2 = ["2.A", "2.B", "2.C", "2.D", "2.E"]
  581. children_3 = [f"3.{i}" for i in "ABCDEFGHIJKLMNOPQR"]
  582. # children_4 = ["4.A"]
  583. # children_5 = ["5.A", "5.B"]
  584. # children_6 = ["6.A", "6.B", "6.C"]
  585. # children_7 = [f"3.{i}" for i in "ABCDEFGHIJKLM"]
  586. main_categories = (
  587. # category code, name and comment, gases, children
  588. ("1", "Crops", ["CH4", "N2O"], children_1),
  589. (
  590. "2",
  591. "Energy use in agriculture",
  592. ["CH4", "N2O", "CO2"],
  593. children_2,
  594. ),
  595. ("3", "Livestock", ["CH4", "N2O"], children_3),
  596. # ("4", "Forest", ["CO2"], children_4),
  597. # (
  598. # "5",
  599. # "Drained organic soils",
  600. # ["N2O", "CO2"],
  601. # children_5,
  602. # ),
  603. # ("6", "Fires", ["CH4", "N2O", "CO2"], children_6),
  604. # (
  605. # "7",
  606. # "Pre and post agricultural production",
  607. # ["CH4", "N2O", "CO2"],
  608. # children_7,
  609. # ),
  610. )
  611. for code, name, gases, children in main_categories:
  612. categories[code] = {
  613. "title": name,
  614. "comment": name,
  615. # "alternative_codes": code.replace(".", ""),
  616. "children": [children],
  617. "info": {"gases": gases},
  618. }
  619. # 1. crops
  620. # all crops category
  621. code_all_crops = "1.A"
  622. codes_crops = [f"1.A.{i}" for i in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]]
  623. categories[code_all_crops] = {
  624. "title": "All crops",
  625. "comment": "All crops",
  626. # "alternative_codes": code_all_crops.replace(".", ""),
  627. "children": [codes_crops],
  628. "info": {"gases": ["CH4", "N2O"]},
  629. }
  630. crops = [
  631. "Wheat",
  632. "Rice",
  633. "Potatoes",
  634. "Millet",
  635. "Barley",
  636. "Maize (corn)",
  637. "Sugar cane",
  638. "Beans, dry",
  639. "Oats",
  640. "Rye",
  641. "Sorghum",
  642. "Soya beans",
  643. ]
  644. crop_burnings = [
  645. True,
  646. True,
  647. False,
  648. False,
  649. False,
  650. True,
  651. True,
  652. False,
  653. False,
  654. False,
  655. False,
  656. False,
  657. ]
  658. rice_cultivations = [
  659. False,
  660. True,
  661. False,
  662. False,
  663. False,
  664. False,
  665. False,
  666. False,
  667. False,
  668. False,
  669. False,
  670. False,
  671. ]
  672. for crop, code, crop_burning, rice_cultivation in zip(
  673. crops, codes_crops, crop_burnings, rice_cultivations
  674. ):
  675. # all crops have at least N2O emissions
  676. gases_main = "N2O"
  677. if crop_burning or rice_cultivation:
  678. gases_main = ["CH4", "N2O"]
  679. # all crops have at least crop residues as child
  680. children_main = [f"{code}.a"]
  681. if crop_burning:
  682. children_main.append(f"{code}.b")
  683. if rice_cultivation:
  684. children_main.append(f"{code}.c")
  685. categories[f"{code}"] = {
  686. "title": f"{crop}",
  687. "comment": f"{crop}",
  688. # "alternative_codes": [f"{code}".replace(".", "")],
  689. "info": {"gases": gases_main},
  690. "children": [children_main],
  691. }
  692. # crop residues (every crop has it)
  693. categories[f"{code}.a.i"] = {
  694. "title": f"{crop} crop residues direct emissions",
  695. "comment": f"{crop} crop residues direct emissions",
  696. # "alternative_codes": [f"{code}.a".replace(".", "")],
  697. "info": {"gases": ["N2O"]},
  698. }
  699. categories[f"{code}.a.ii"] = {
  700. "title": f"{crop} crop residues indirect emissions",
  701. "comment": f"{crop} crop residues indirect emissions",
  702. # "alternative_codes": [f"{code}.a.i".replace(".", "")],
  703. "info": {"gases": ["N2O"]},
  704. }
  705. categories[f"{code}.a"] = {
  706. "title": f"{crop} crop residues",
  707. "comment": f"{crop} crop residues",
  708. # "alternative_codes": [f"{code}.a".replace(".", "")],
  709. "info": {"gases": ["N2O"]},
  710. "children": [[f"{code}.a.ii", f"{code}.a.i"]],
  711. }
  712. if crop_burning:
  713. categories[f"{code}.b"] = {
  714. "title": f"{crop} burning crop residues",
  715. "comment": f"{crop} burning crop residues",
  716. # "alternative_codes": [f"{code}.b".replace(".", "")],
  717. "info": {"gases": ["CH4", "N2O"]},
  718. }
  719. if rice_cultivation:
  720. categories[f"{code}.c"] = {
  721. "title": "Rice cultivation",
  722. "comment": "Rice cultivation",
  723. # "alternative_codes": [f"{code}.c".replace(".", "")],
  724. "info": {"gases": ["CH4"]},
  725. }
  726. # synthetic fertilisers
  727. codes_synthetic_fertilisers = ["1.B", "1.B.1", "1.B.2", "1.B.2.a", "1.B.2.b"]
  728. names = [
  729. "Synthetic fertilisers",
  730. "Direct emissions",
  731. "Indirect emissions",
  732. "Indirect emissions that volatilise",
  733. "Indirect emissions that leach",
  734. ]
  735. children_cats = [["1.B.1", "1.B.2"], None, ["1.B.2.a", "1.B.2.b"], None, None]
  736. for code, name, child_cat in zip(codes_synthetic_fertilisers, names, children_cats):
  737. categories[code] = {
  738. "title": name,
  739. "comment": name,
  740. # "alternative_codes": [code.replace(".", "")],
  741. "info": {"gases": ["N2O"]},
  742. }
  743. if child_cat:
  744. categories[code]["children"] = [child_cat]
  745. # 2. energy use
  746. names = [
  747. "Natural gas",
  748. "Electricity",
  749. "Coal",
  750. "Heat",
  751. "Petroleum",
  752. ]
  753. codes = children_2
  754. for name, code in zip(names, codes):
  755. categories[code] = {
  756. "title": name,
  757. "comment": name,
  758. # "alternative_codes": code.replace(".", ""),
  759. "info": {"gases": ["CH4", "N2O", "CO2"]},
  760. }
  761. # 3 livestock
  762. animals = [
  763. "Asses",
  764. "Camels",
  765. "Cattle, dairy",
  766. "Cattle, non-dairy",
  767. "Chickens, broilers",
  768. "Chickens, layers",
  769. "Goats",
  770. "Horses",
  771. "Mules and hinnies",
  772. "Sheep",
  773. "Llamas",
  774. "Chickens",
  775. "Poultry Birds",
  776. "Buffalo",
  777. "Ducks",
  778. "Swine, breeding",
  779. "Swine, market",
  780. "Turkeys",
  781. ]
  782. codes_animals = [f"3.{i}" for i in "ABCDEFGHIJKLMNOPQR"]
  783. enteric_fermentation = [
  784. "Asses",
  785. "Camels",
  786. "Cattle, dairy",
  787. "Cattle, non-dairy",
  788. "Goats",
  789. "Horses",
  790. "Sheep",
  791. "Mules and hinnies",
  792. "Buffalo",
  793. "Swine, breeding",
  794. "Swine, market",
  795. "Llamas",
  796. ]
  797. for animal, code in zip(animals, codes_animals):
  798. if animal in enteric_fermentation:
  799. gases = ["CH4"]
  800. animal_children = [f"{code}.{i}" for i in "1234"]
  801. categories[f"{code}.4"] = {
  802. "title": f"{animal} enteric fermentation",
  803. "comment": f"{animal} enteric fermentation",
  804. # "alternative_codes" : code.replace(".", ""),
  805. "info": {"gases": gases},
  806. }
  807. else:
  808. gases = ["N2O"]
  809. animal_children = [f"{code}.{i}" for i in "123"]
  810. categories[code] = {
  811. "title": animal,
  812. "comment": animal,
  813. # "alternative_codes" : code.replace(".", ""),
  814. "info": {"gases": gases},
  815. "children": [animal_children],
  816. }
  817. # manure management branch
  818. manure_management_children = [f"{code}.1.{i}" for i in "abc"]
  819. categories[f"{code}.1"] = {
  820. "title": f"{animal} manure management",
  821. "comment": f"{animal} manure management",
  822. # "alternative_codes" : code.replace(".", ""),
  823. "info": {"gases": gases},
  824. "children": [manure_management_children],
  825. }
  826. categories[f"{code}.1.a"] = {
  827. "title": f"{animal} decomposition of organic matter",
  828. "comment": f"{animal} decomposition of organic matter",
  829. # "alternative_codes" : code.replace(".", ""),
  830. "info": {"gases": "CH4"},
  831. }
  832. categories[f"{code}.1.b"] = {
  833. "title": f"{animal} manure management (Direct emissions N2O)",
  834. "comment": f"{animal} manure management (Direct emissions N2O)",
  835. # "alternative_codes" : code.replace(".", ""),
  836. "info": {"gases": "N2O"},
  837. }
  838. categories[f"{code}.1.c"] = {
  839. "title": f"{animal} manure management (Indirect emissions N2O)",
  840. "comment": f"{animal} manure management (Indirect emissions N2O)",
  841. # "alternative_codes" : code.replace(".", ""),
  842. "info": {"gases": "N2O"},
  843. }
  844. # manure left on pasture branch
  845. manure_left_on_pasture_children = [f"{code}.2.{i}" for i in "ab"]
  846. categories[f"{code}.2"] = {
  847. "title": f"{animal} manure left on pasture",
  848. "comment": f"{animal} manure left on pasture",
  849. # "alternative_codes" : code.replace(".", ""),
  850. "info": {"gases": "N2O"},
  851. "children": [manure_left_on_pasture_children],
  852. }
  853. categories[f"{code}.2.a"] = {
  854. "title": f"{animal} manure left on pasture (direct emissions N2O)",
  855. "comment": f"{animal} manure left on pasture (direct emissions N2O)",
  856. # "alternative_codes" : code.replace(".", ""),
  857. "info": {"gases": "N2O"},
  858. }
  859. categories[f"{code}.2.b"] = {
  860. "title": f"{animal} manure left on pasture (indirect emissions N2O)",
  861. "comment": f"{animal} manure left on pasture (indirect emissions N2O)",
  862. # "alternative_codes" : code.replace(".", ""),
  863. "info": {"gases": "N2O"},
  864. "children": [[f"{code}.2.b.i", f"{code}.2.b.ii"]],
  865. }
  866. categories[f"{code}.2.b.i"] = {
  867. "title": (
  868. f"{animal} manure left on pasture "
  869. f"(indirect emissions, N2O that leaches)"
  870. ),
  871. "comment": (
  872. f"{animal} manure left on pasture (indirect "
  873. f"emissions, N2O that leaches)"
  874. ),
  875. # "alternative_codes" : code.replace(".", ""),
  876. "info": {"gases": "N2O"},
  877. }
  878. categories[f"{code}.2.b.ii"] = {
  879. "title": (
  880. f"{animal} manure left on pasture "
  881. f"(indirect emissions, N2O that volatilises)"
  882. ),
  883. "comment": (
  884. f"{animal} manure left on pasture (indirect "
  885. f"emissions, N2O that volatilises)"
  886. ),
  887. # "alternative_codes" : code.replace(".", ""),
  888. "info": {"gases": "N2O"},
  889. }
  890. # manure applied branch
  891. manure_applied_children = [f"{code}.3.{i}" for i in "ab"]
  892. categories[f"{code}.3"] = {
  893. "title": f"{animal} manure applied",
  894. "comment": f"{animal} manure applied",
  895. # "alternative_codes" : code.replace(".", ""),
  896. "info": {"gases": "N2O"},
  897. "children": [manure_applied_children],
  898. }
  899. categories[f"{code}.3.a"] = {
  900. "title": f"{animal} manure applied (direct emissions N2O)",
  901. "comment": f"{animal} manure applied (direct emissions N2O)",
  902. # "alternative_codes" : code.replace(".", ""),
  903. "info": {"gases": "N2O"},
  904. }
  905. categories[f"{code}.3.b"] = {
  906. "title": f"{animal} manure applied (indirect emissions N2O)",
  907. "comment": f"{animal} manure applied (indirect emissions N2O)",
  908. # "alternative_codes" : code.replace(".", ""),
  909. "info": {"gases": "N2O"},
  910. "children": [[f"{code}.3.b.i", f"{code}.3.b.ii"]],
  911. }
  912. categories[f"{code}.3.b.i"] = {
  913. "title": (
  914. f"{animal} manure applied " f"(indirect emissions, N2O that leaches)"
  915. ),
  916. "comment": (
  917. f"{animal} manure applied (indirect " f"emissions, N2O that leaches)"
  918. ),
  919. # "alternative_codes" : code.replace(".", ""),
  920. "info": {"gases": "N2O"},
  921. }
  922. categories[f"{code}.3.b.ii"] = {
  923. "title": (
  924. f"{animal} manure applied "
  925. f"(indirect emissions, N2O that volatilises)"
  926. ),
  927. "comment": (
  928. f"{animal} manure applied (indirect "
  929. f"emissions, N2O that volatilises)"
  930. ),
  931. # "alternative_codes" : code.replace(".", ""),
  932. "info": {"gases": "N2O"},
  933. }
  934. # forests
  935. categories["4"] = {
  936. "title": "Carbon stock change in forests",
  937. "comment": "Carbon stock change in forests",
  938. "info": {"gases": "CO2"},
  939. "children": [["4.A", "4.B"]],
  940. }
  941. categories["4.A"] = {
  942. "title": "Forest land",
  943. "comment": "Forest land",
  944. "info": {"gases": "CO2"},
  945. }
  946. categories["4.B"] = {
  947. "title": "Net Forest conversion",
  948. "comment": "Net Forest conversion",
  949. "info": {"gases": "CO2"},
  950. }
  951. # drained organic soils
  952. categories["5"] = {
  953. "title": "Drained organic soils",
  954. "comment": "Drained organic soils",
  955. "info": {"gases": "CO2"},
  956. "children": [["5.A", "5.B"]],
  957. }
  958. categories["5.A"] = {
  959. "title": "Drained grassland",
  960. "comment": "Drained grassland",
  961. "info": {"gases": ["CO2", "N2O"]},
  962. }
  963. categories["5.B"] = {
  964. "title": "Drained cropland",
  965. "comment": "Drained cropland",
  966. "info": {"gases": ["CO2", "N2O"]},
  967. }
  968. # 6 Fires
  969. # Forest fires
  970. forest_fires_children = ["Humid tropical forests", "Other forests"]
  971. forest_fires_children_codes = ["6.A.1", "6.A.2"]
  972. for cat_name, code in zip(forest_fires_children, forest_fires_children_codes):
  973. categories[code] = {
  974. "title": cat_name,
  975. "comment": cat_name,
  976. "info": {"gases": ["CO2", "N2O", "CH4"]},
  977. }
  978. categories["6.A"] = {
  979. "title": "Forest fires",
  980. "comment": "Forest fires",
  981. "info": {"gases": ["CO2", "N2O", "CH4"]},
  982. "children": [forest_fires_children_codes],
  983. }
  984. # Savanna fires
  985. savanna_fires_children = [
  986. "Closed shrubland",
  987. "Grassland",
  988. "Open shrubland",
  989. "Savanna",
  990. "Woody savanna",
  991. ]
  992. savanna_fires_children_codes = ["6.B.1", "6.B.2", "6.B.3", "6.B.4", "6.B.5"]
  993. for cat_name, code in zip(savanna_fires_children, savanna_fires_children_codes):
  994. categories[code] = {
  995. "title": cat_name,
  996. "comment": cat_name,
  997. "info": {"gases": ["CO2", "N2O", "CH4"]},
  998. }
  999. categories["6.B"] = {
  1000. "title": "Savanna fires",
  1001. "comment": "Savanna fires",
  1002. "info": {"gases": ["CO2", "N2O", "CH4"]},
  1003. "children": [savanna_fires_children_codes],
  1004. }
  1005. # fires in organic soils
  1006. categories["6.C"] = {
  1007. "title": "Fires in organic soils",
  1008. "comment": "Fires in organic soils",
  1009. "info": {"gases": ["CO2", "N2O", "CH4"]},
  1010. }
  1011. # 6 fires
  1012. categories["6"] = {
  1013. "title": "Fires",
  1014. "comment": "Fires",
  1015. "info": {"gases": ["CO2", "N2O", "CH4"]},
  1016. "children": [["6.A", "6.B", "6.C"]],
  1017. }
  1018. # 7 pre and post production
  1019. pre_post_production_categories = [
  1020. "Fertilizers Manufacturing",
  1021. "Food Transport",
  1022. "Food Retail",
  1023. "Food Household Consumption",
  1024. "Solid Food Waste",
  1025. "Domestic Wastewater",
  1026. "Industrial Wastewater",
  1027. "Incineration",
  1028. "Pre- and Post- Production",
  1029. "Energy Use (Pre- and Post-Production)",
  1030. "Agrifood Systems Waste Disposal",
  1031. "Cold Chain F-Gas",
  1032. "Pesticides Manufacturing",
  1033. "Food Processing",
  1034. "Food Packaging",
  1035. ]
  1036. pre_post_production_categories_codes = ["7." + i for i in "ABCDEFGHIJKLMNO"]
  1037. pre_post_production_categories_gases = [
  1038. ["CO2", "N2O", "KYOTOGHG (AR5GWP100)"],
  1039. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)", "FGASES (AR5GWP100)"],
  1040. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)", "FGASES (AR5GWP100)"],
  1041. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)", "FGASES (AR5GWP100)"],
  1042. ["KYOTOGHG (AR5GWP100)", "CH4"],
  1043. ["KYOTOGHG (AR5GWP100)", "CH4", "N2O"],
  1044. ["KYOTOGHG (AR5GWP100)", "CH4", "N2O"],
  1045. ["CO2", "KYOTOGHG (AR5GWP100)"], # incineration
  1046. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)", "FGASES (AR5GWP100)"],
  1047. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)"],
  1048. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)"],
  1049. ["FGASES (AR5GWP100)"],
  1050. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)"],
  1051. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)", "FGASES (AR5GWP100)"],
  1052. ["CO2", "CH4", "N2O", "KYOTOGHG (AR5GWP100)"],
  1053. ]
  1054. for cat_name, code, gases in zip(
  1055. pre_post_production_categories,
  1056. pre_post_production_categories_codes,
  1057. pre_post_production_categories_gases,
  1058. ):
  1059. categories[code] = {
  1060. "title": cat_name,
  1061. "comment": cat_name,
  1062. "info": {"gases": gases},
  1063. }
  1064. categories["7"] = {
  1065. "title": "Pre and post agricultural production",
  1066. "comment": "Pre and post agricultural production",
  1067. "info": {
  1068. "gases": [
  1069. "CO2",
  1070. "CH4",
  1071. "N2O",
  1072. "KYOTOGHG (AR5GWP100)",
  1073. "FGASES (AR5GWP100)",
  1074. ],
  1075. },
  1076. "children": [pre_post_production_categories_codes],
  1077. }
  1078. spec["categories"] = categories
  1079. fao_cats = cc.HierarchicalCategorization.from_spec(spec.copy())
  1080. # run print(fao_cats.show_as_tree())
  1081. fao_cats.to_python("FAO.py")
  1082. fao_cats.to_yaml("FAO.yaml")
  1083. pass