brightpath 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- brightpath/__init__.py +9 -0
- brightpath/bwconverter.py +616 -0
- brightpath/data/export/correspondence_biosphere_flows.yaml +247 -0
- brightpath/data/export/ecoinvent_to_uvek_mapping.csv +659 -0
- brightpath/data/export/ei_transport.csv +277 -0
- brightpath/data/export/flows_biosphere_39.csv +4711 -0
- brightpath/data/export/simapro-biosphere.json +2842 -0
- brightpath/data/export/simapro-technosphere-3.5.csv +46564 -0
- brightpath/data/export/simapro_blacklist.yaml +15 -0
- brightpath/data/export/simapro_ei_exceptions.yaml +5 -0
- brightpath/data/export/simapro_fields.yaml +37 -0
- brightpath/data/export/simapro_headers.yaml +15 -0
- brightpath/data/export/simapro_subcompartments.yaml +16 -0
- brightpath/data/export/simapro_units.yaml +15 -0
- brightpath/data/export/uvek_blacklist.yaml +7 -0
- brightpath/data/export/uvek_conversion_factors.yaml +31 -0
- brightpath/data/export/waste_exchange_names.yaml +11 -0
- brightpath/simaproconverter.py +463 -0
- brightpath/utils.py +1181 -0
- brightpath-0.0.1.dist-info/METADATA +140 -0
- brightpath-0.0.1.dist-info/RECORD +24 -0
- brightpath-0.0.1.dist-info/WHEEL +5 -0
- brightpath-0.0.1.dist-info/licenses/LICENSE +29 -0
- brightpath-0.0.1.dist-info/top_level.txt +1 -0
brightpath/__init__.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
__all__ = ("BrightwayConverter", "SimaproConverter", "DATA_DIR")
|
|
2
|
+
__version__ = (0, 0, 2)
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
DATA_DIR = Path(__file__).resolve().parent / "data"
|
|
7
|
+
|
|
8
|
+
from .bwconverter import BrightwayConverter
|
|
9
|
+
from .simaproconverter import SimaproConverter
|
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains the class BrightwayConverter, which is used to convert
|
|
3
|
+
Brightway2 inventories to Simapro CSV files.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import csv
|
|
7
|
+
import datetime
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
from .utils import (
|
|
11
|
+
add_distri_transport,
|
|
12
|
+
check_exchanges_for_conversion,
|
|
13
|
+
convert_sd_to_sd2,
|
|
14
|
+
find_production_exchange,
|
|
15
|
+
flag_exchanges,
|
|
16
|
+
format_exchange_name,
|
|
17
|
+
get_biosphere_exchanges,
|
|
18
|
+
get_simapro_biosphere,
|
|
19
|
+
get_simapro_ecoinvent_blacklist,
|
|
20
|
+
get_simapro_fields_list,
|
|
21
|
+
get_simapro_headers,
|
|
22
|
+
get_simapro_subcompartments,
|
|
23
|
+
get_simapro_technosphere,
|
|
24
|
+
get_simapro_uncertainty_type,
|
|
25
|
+
get_simapro_units,
|
|
26
|
+
get_subcategory,
|
|
27
|
+
get_technosphere_exchanges,
|
|
28
|
+
import_bw_inventories,
|
|
29
|
+
is_a_waste_treatment,
|
|
30
|
+
is_activity_waste_treatment,
|
|
31
|
+
is_blacklisted,
|
|
32
|
+
load_inventory_metadata,
|
|
33
|
+
print_unused_exchanges,
|
|
34
|
+
round_floats_in_string,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class BrightwayConverter:
|
|
39
|
+
"""Convert Brightway2 inventories to SimaPro CSV files.
|
|
40
|
+
|
|
41
|
+
The converter loads inventories exported from Brightway2 and prepares
|
|
42
|
+
them for the SimaPro import format. The instance keeps references to the
|
|
43
|
+
different lookup tables that are needed throughout the conversion.
|
|
44
|
+
|
|
45
|
+
:param filepath: Path to the Brightway inventory spreadsheet.
|
|
46
|
+
:type filepath: str | None
|
|
47
|
+
:param data: Brightway inventories provided directly instead of loading
|
|
48
|
+
them from ``filepath``.
|
|
49
|
+
:type data: list | None
|
|
50
|
+
:param metadata: Optional path to a YAML file containing additional
|
|
51
|
+
metadata to append to the export.
|
|
52
|
+
:type metadata: str | None
|
|
53
|
+
:param ecoinvent_version: Version string of the ecoinvent database the
|
|
54
|
+
inventories are linked to.
|
|
55
|
+
:type ecoinvent_version: str
|
|
56
|
+
:param export_dir: Directory where generated SimaPro CSV files are saved.
|
|
57
|
+
:type export_dir: str | None
|
|
58
|
+
:ivar filepath: Path to the Brightway inventory spreadsheet.
|
|
59
|
+
:vartype filepath: str | None
|
|
60
|
+
:ivar inventories: Brightway activities that are going to be converted.
|
|
61
|
+
:vartype inventories: list[dict] | None
|
|
62
|
+
:ivar simapro_blacklist: Exchanges that should not be exported.
|
|
63
|
+
:vartype simapro_blacklist: dict
|
|
64
|
+
:ivar simapro_fields: Order and structure of SimaPro sections.
|
|
65
|
+
:vartype simapro_fields: list[str]
|
|
66
|
+
:ivar simapro_units: Mapping of Brightway units to SimaPro units.
|
|
67
|
+
:vartype simapro_units: dict[str, str]
|
|
68
|
+
:ivar simapro_headers: Header rows used when writing the CSV file.
|
|
69
|
+
:vartype simapro_headers: list[str]
|
|
70
|
+
:ivar simapro_technosphere: Mapping from technosphere exchanges to
|
|
71
|
+
SimaPro names.
|
|
72
|
+
:vartype simapro_technosphere: dict[tuple[str, str], str]
|
|
73
|
+
:ivar simapro_biosphere: Mapping from biosphere exchanges to SimaPro
|
|
74
|
+
names.
|
|
75
|
+
:vartype simapro_biosphere: dict[str, str]
|
|
76
|
+
:ivar simapro_subcompartment: Mapping of biosphere subcompartments to
|
|
77
|
+
SimaPro names.
|
|
78
|
+
:vartype simapro_subcompartment: dict[str, str]
|
|
79
|
+
:ivar ei_version: Version of the ecoinvent database in use.
|
|
80
|
+
:vartype ei_version: str
|
|
81
|
+
:ivar metadata: Optional metadata loaded from the YAML file.
|
|
82
|
+
:vartype metadata: dict | None
|
|
83
|
+
:ivar export_dir: Output directory for converted CSV files.
|
|
84
|
+
:vartype export_dir: pathlib.Path
|
|
85
|
+
"""
|
|
86
|
+
|
|
87
|
+
def __init__(
|
|
88
|
+
self,
|
|
89
|
+
filepath: str = None,
|
|
90
|
+
data: list = None,
|
|
91
|
+
metadata: str = None,
|
|
92
|
+
ecoinvent_version: str = "3.9",
|
|
93
|
+
export_dir: str = None,
|
|
94
|
+
):
|
|
95
|
+
"""Instantiate a converter that targets the SimaPro CSV format.
|
|
96
|
+
|
|
97
|
+
When ``filepath`` is provided the inventories are loaded from the
|
|
98
|
+
spreadsheet using :func:`brightpath.utils.import_bw_inventories`. If
|
|
99
|
+
``filepath`` is omitted, pre-loaded ``data`` can be supplied instead.
|
|
100
|
+
Optional ``metadata`` is validated and attached to the export.
|
|
101
|
+
|
|
102
|
+
:param filepath: Path to the Brightway inventory spreadsheet file.
|
|
103
|
+
:type filepath: str | None
|
|
104
|
+
:param data: Inventories loaded in memory. Used when ``filepath`` is
|
|
105
|
+
``None``.
|
|
106
|
+
:type data: list | None
|
|
107
|
+
:param metadata: Path to the metadata YAML file.
|
|
108
|
+
:type metadata: str | None
|
|
109
|
+
:param ecoinvent_version: Version of the linked ecoinvent database.
|
|
110
|
+
:type ecoinvent_version: str
|
|
111
|
+
:param export_dir: Directory where SimaPro exports will be written.
|
|
112
|
+
:type export_dir: str | None
|
|
113
|
+
:raises FileNotFoundError: If the metadata file does not exist.
|
|
114
|
+
:raises ValueError: If the metadata file is not a YAML document.
|
|
115
|
+
"""
|
|
116
|
+
self.filepath = filepath
|
|
117
|
+
self.inventories = import_bw_inventories(filepath) if self.filepath else data
|
|
118
|
+
self.simapro_blacklist = get_simapro_ecoinvent_blacklist()
|
|
119
|
+
self.simapro_fields = get_simapro_fields_list()
|
|
120
|
+
self.simapro_units = get_simapro_units()
|
|
121
|
+
self.simapro_headers = get_simapro_headers()
|
|
122
|
+
self.simapro_technosphere = get_simapro_technosphere()
|
|
123
|
+
self.simapro_biosphere = get_simapro_biosphere()
|
|
124
|
+
self.simapro_subcompartment = get_simapro_subcompartments()
|
|
125
|
+
self.ei_version = ecoinvent_version
|
|
126
|
+
|
|
127
|
+
if metadata:
|
|
128
|
+
self.metadata = load_inventory_metadata(metadata)
|
|
129
|
+
|
|
130
|
+
# export directory is the current working
|
|
131
|
+
# directory unless specified otherwise
|
|
132
|
+
self.export_dir = Path(export_dir) or Path.cwd()
|
|
133
|
+
|
|
134
|
+
def format_inventories_for_simapro(self, database: str):
|
|
135
|
+
"""Transform the Brightway inventories into the SimaPro structure.
|
|
136
|
+
|
|
137
|
+
This method orchestrates the conversion of each activity in the
|
|
138
|
+
Brightway dataset into the row-based structure expected by SimaPro.
|
|
139
|
+
The resulting structure is compatible with the CSV export performed
|
|
140
|
+
by :meth:`convert_to_simapro`.
|
|
141
|
+
|
|
142
|
+
:param database: Name of the target database to link to. Valid values
|
|
143
|
+
are ``"ecoinvent"`` and ``"uvek"``.
|
|
144
|
+
:type database: str
|
|
145
|
+
:return: Rows ready to be written to a SimaPro CSV file.
|
|
146
|
+
:rtype: list[list[str]]
|
|
147
|
+
:raises ValueError: If required information is missing from the
|
|
148
|
+
inventories.
|
|
149
|
+
"""
|
|
150
|
+
|
|
151
|
+
rows = [
|
|
152
|
+
(
|
|
153
|
+
[
|
|
154
|
+
item.replace(
|
|
155
|
+
"today_date", datetime.datetime.today().strftime("%d.%m.%Y")
|
|
156
|
+
)
|
|
157
|
+
]
|
|
158
|
+
if item.startswith("{Date")
|
|
159
|
+
else [item]
|
|
160
|
+
)
|
|
161
|
+
for item in self.simapro_headers
|
|
162
|
+
]
|
|
163
|
+
rows.append([])
|
|
164
|
+
|
|
165
|
+
for activity in self.inventories:
|
|
166
|
+
|
|
167
|
+
# first, add transport, if uvek
|
|
168
|
+
if database == "uvek":
|
|
169
|
+
activity = add_distri_transport(activity)
|
|
170
|
+
# and flag exchanges
|
|
171
|
+
activity = flag_exchanges(activity)
|
|
172
|
+
dataset_name = ""
|
|
173
|
+
is_a_waste_treatment_activity = is_activity_waste_treatment(
|
|
174
|
+
activity, database
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
for field in self.simapro_fields:
|
|
178
|
+
if is_a_waste_treatment_activity is True and field == "Products":
|
|
179
|
+
continue
|
|
180
|
+
|
|
181
|
+
if (
|
|
182
|
+
is_a_waste_treatment_activity is False
|
|
183
|
+
and field == "Waste treatment"
|
|
184
|
+
):
|
|
185
|
+
continue
|
|
186
|
+
|
|
187
|
+
rows.append([field])
|
|
188
|
+
if field in ["Process", "End"]:
|
|
189
|
+
rows.append([])
|
|
190
|
+
continue
|
|
191
|
+
|
|
192
|
+
if field == "Process name":
|
|
193
|
+
dataset_name = format_exchange_name(
|
|
194
|
+
activity["name"],
|
|
195
|
+
activity["reference product"],
|
|
196
|
+
activity["location"],
|
|
197
|
+
activity["unit"],
|
|
198
|
+
database,
|
|
199
|
+
)
|
|
200
|
+
rows.extend(
|
|
201
|
+
[
|
|
202
|
+
[dataset_name],
|
|
203
|
+
[],
|
|
204
|
+
]
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
if field == "Type":
|
|
208
|
+
rows.extend(
|
|
209
|
+
[
|
|
210
|
+
["Unit process"],
|
|
211
|
+
[],
|
|
212
|
+
]
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
if field == "Comment":
|
|
216
|
+
string = ""
|
|
217
|
+
if activity.get("comment"):
|
|
218
|
+
string = f"{round_floats_in_string(activity['comment'])} "
|
|
219
|
+
|
|
220
|
+
if activity.get("source"):
|
|
221
|
+
string += f"Source: {activity['source']} "
|
|
222
|
+
# remove line breaks in string
|
|
223
|
+
string = string.replace("\n", " ")
|
|
224
|
+
rows.extend(
|
|
225
|
+
[
|
|
226
|
+
[string],
|
|
227
|
+
[],
|
|
228
|
+
]
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
if field == "Category type":
|
|
232
|
+
prod_exchange = find_production_exchange(activity)
|
|
233
|
+
if "simapro category" in prod_exchange:
|
|
234
|
+
rows.extend(
|
|
235
|
+
[
|
|
236
|
+
[prod_exchange["simapro category"].split("/")[0]],
|
|
237
|
+
[],
|
|
238
|
+
]
|
|
239
|
+
)
|
|
240
|
+
else:
|
|
241
|
+
rows.extend([["Others"], []])
|
|
242
|
+
|
|
243
|
+
if field == "Geography":
|
|
244
|
+
rows.extend(
|
|
245
|
+
[
|
|
246
|
+
[activity["location"]],
|
|
247
|
+
[],
|
|
248
|
+
]
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
if field == "Date":
|
|
252
|
+
rows.extend(
|
|
253
|
+
[
|
|
254
|
+
[f"{datetime.datetime.today():%d.%m.%Y}"],
|
|
255
|
+
[],
|
|
256
|
+
]
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
if field in (
|
|
260
|
+
"Time period",
|
|
261
|
+
"Record",
|
|
262
|
+
"Generator",
|
|
263
|
+
"Cut off rules",
|
|
264
|
+
"Capital goods",
|
|
265
|
+
"Technology",
|
|
266
|
+
"Representativeness",
|
|
267
|
+
"Boundary with nature",
|
|
268
|
+
"Infrastructure",
|
|
269
|
+
"External documents",
|
|
270
|
+
"System description",
|
|
271
|
+
"Allocation rules",
|
|
272
|
+
"Literature references",
|
|
273
|
+
"Collection method",
|
|
274
|
+
"Data treatment",
|
|
275
|
+
"Verification",
|
|
276
|
+
):
|
|
277
|
+
if field.lower() in activity:
|
|
278
|
+
rows.extend(
|
|
279
|
+
[
|
|
280
|
+
[activity[field.lower()]],
|
|
281
|
+
[],
|
|
282
|
+
]
|
|
283
|
+
)
|
|
284
|
+
else:
|
|
285
|
+
if field == "Infrastructure":
|
|
286
|
+
rows.extend([["No"], []])
|
|
287
|
+
elif (
|
|
288
|
+
field == "System description"
|
|
289
|
+
and "system description" in self.metadata
|
|
290
|
+
):
|
|
291
|
+
rows.extend(
|
|
292
|
+
[[self.metadata["system description"]["name"]], []]
|
|
293
|
+
)
|
|
294
|
+
elif (
|
|
295
|
+
field == "Literature references"
|
|
296
|
+
and "literature reference" in self.metadata
|
|
297
|
+
):
|
|
298
|
+
rows.extend(
|
|
299
|
+
[[self.metadata["literature reference"]["name"]], []]
|
|
300
|
+
)
|
|
301
|
+
else:
|
|
302
|
+
rows.extend([["Unspecified"], []])
|
|
303
|
+
|
|
304
|
+
if field in (
|
|
305
|
+
"Final waste flows",
|
|
306
|
+
"Non material emission",
|
|
307
|
+
"Social issues",
|
|
308
|
+
"Economic issues",
|
|
309
|
+
):
|
|
310
|
+
rows.append([])
|
|
311
|
+
|
|
312
|
+
if field == "Waste treatment":
|
|
313
|
+
prod_exchange = find_production_exchange(activity)
|
|
314
|
+
category = get_subcategory(prod_exchange["simapro category"])
|
|
315
|
+
|
|
316
|
+
if prod_exchange["amount"] < 0:
|
|
317
|
+
prod_exchange["amount"] *= -1
|
|
318
|
+
|
|
319
|
+
rows.extend(
|
|
320
|
+
[
|
|
321
|
+
[
|
|
322
|
+
dataset_name,
|
|
323
|
+
self.simapro_units[prod_exchange["unit"]],
|
|
324
|
+
"{:.3E}".format(prod_exchange["amount"]),
|
|
325
|
+
"100",
|
|
326
|
+
"not defined",
|
|
327
|
+
category,
|
|
328
|
+
"not defined",
|
|
329
|
+
],
|
|
330
|
+
[],
|
|
331
|
+
]
|
|
332
|
+
)
|
|
333
|
+
prod_exchange["used"] = True
|
|
334
|
+
|
|
335
|
+
if field == "Products":
|
|
336
|
+
prod_exchange = find_production_exchange(activity)
|
|
337
|
+
category = get_subcategory(prod_exchange["simapro category"])
|
|
338
|
+
rows.extend(
|
|
339
|
+
[
|
|
340
|
+
[
|
|
341
|
+
dataset_name,
|
|
342
|
+
self.simapro_units[prod_exchange["unit"]],
|
|
343
|
+
"{:.3E}".format(prod_exchange["amount"]),
|
|
344
|
+
"100",
|
|
345
|
+
"not defined",
|
|
346
|
+
category,
|
|
347
|
+
"not defined",
|
|
348
|
+
],
|
|
349
|
+
[],
|
|
350
|
+
]
|
|
351
|
+
)
|
|
352
|
+
prod_exchange["used"] = True
|
|
353
|
+
|
|
354
|
+
if field in ["Materials/fuels", "Electricity/heat"]:
|
|
355
|
+
|
|
356
|
+
if field == "Materials/fuels":
|
|
357
|
+
techno_excs = list(
|
|
358
|
+
filter(
|
|
359
|
+
lambda x: x["unit"]
|
|
360
|
+
not in ["megajoule", "kilowatt hour"],
|
|
361
|
+
get_technosphere_exchanges(activity),
|
|
362
|
+
)
|
|
363
|
+
)
|
|
364
|
+
else:
|
|
365
|
+
techno_excs = list(
|
|
366
|
+
filter(
|
|
367
|
+
lambda x: x["unit"] in ["megajoule", "kilowatt hour"],
|
|
368
|
+
get_technosphere_exchanges(activity),
|
|
369
|
+
)
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
techno_excs = list(
|
|
373
|
+
filter(
|
|
374
|
+
lambda x: is_blacklisted(x, database) is False,
|
|
375
|
+
list(techno_excs),
|
|
376
|
+
)
|
|
377
|
+
)
|
|
378
|
+
techno_excs = check_exchanges_for_conversion(techno_excs, database)
|
|
379
|
+
|
|
380
|
+
for exc in filter(
|
|
381
|
+
lambda x: is_a_waste_treatment(x["name"], database=database)
|
|
382
|
+
is not True,
|
|
383
|
+
techno_excs,
|
|
384
|
+
):
|
|
385
|
+
exchange_name = format_exchange_name(
|
|
386
|
+
exc["name"],
|
|
387
|
+
exc["reference product"],
|
|
388
|
+
exc.get("location", "GLO"),
|
|
389
|
+
exc["unit"],
|
|
390
|
+
database,
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
u_type = get_simapro_uncertainty_type(
|
|
394
|
+
exc.get("uncertainty type")
|
|
395
|
+
)
|
|
396
|
+
|
|
397
|
+
if is_a_waste_treatment_activity is True and exc["amount"] < 0:
|
|
398
|
+
exc["amount"] *= -1
|
|
399
|
+
|
|
400
|
+
rows.append(
|
|
401
|
+
[
|
|
402
|
+
f"{exchange_name}",
|
|
403
|
+
self.simapro_units[exc["unit"]],
|
|
404
|
+
"{:.3E}".format(exc["amount"]),
|
|
405
|
+
u_type,
|
|
406
|
+
"{:.3E}".format(
|
|
407
|
+
convert_sd_to_sd2(exc.get("scale", 1), u_type)
|
|
408
|
+
),
|
|
409
|
+
"{:.3E}".format(exc.get("min", 0)),
|
|
410
|
+
"{:.3E}".format(exc.get("max", 0)),
|
|
411
|
+
exc.get("comment"),
|
|
412
|
+
]
|
|
413
|
+
)
|
|
414
|
+
exc["used"] = True
|
|
415
|
+
|
|
416
|
+
rows.append([])
|
|
417
|
+
|
|
418
|
+
if field == "Resources":
|
|
419
|
+
biosphere_excs = get_biosphere_exchanges(
|
|
420
|
+
activity, "natural resource"
|
|
421
|
+
)
|
|
422
|
+
for exc in filter(
|
|
423
|
+
lambda x: is_blacklisted(x, database) is False, biosphere_excs
|
|
424
|
+
):
|
|
425
|
+
|
|
426
|
+
u_type = get_simapro_uncertainty_type(
|
|
427
|
+
exc.get("uncertainty type")
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
if len(exc["categories"]) > 1:
|
|
431
|
+
sub_compartment = self.simapro_subcompartment[
|
|
432
|
+
exc["categories"][1]
|
|
433
|
+
]
|
|
434
|
+
else:
|
|
435
|
+
sub_compartment = ""
|
|
436
|
+
|
|
437
|
+
rows.append(
|
|
438
|
+
[
|
|
439
|
+
f"{self.simapro_biosphere.get(exc['name'], exc['name'])}",
|
|
440
|
+
sub_compartment,
|
|
441
|
+
self.simapro_units[exc["unit"]],
|
|
442
|
+
"{:.3E}".format(exc["amount"]),
|
|
443
|
+
u_type,
|
|
444
|
+
"{:.3E}".format(
|
|
445
|
+
convert_sd_to_sd2(exc.get("scale", 1), u_type)
|
|
446
|
+
),
|
|
447
|
+
"{:.3E}".format(exc.get("min", 0)),
|
|
448
|
+
"{:.3E}".format(exc.get("max", 0)),
|
|
449
|
+
exc.get("comment"),
|
|
450
|
+
]
|
|
451
|
+
)
|
|
452
|
+
exc["used"] = True
|
|
453
|
+
rows.append([])
|
|
454
|
+
|
|
455
|
+
if field.startswith("Emissions to"):
|
|
456
|
+
biosphere_excs = get_biosphere_exchanges(
|
|
457
|
+
activity, field.split(" ")[-1].lower()
|
|
458
|
+
)
|
|
459
|
+
for exc in filter(
|
|
460
|
+
lambda x: is_blacklisted(x, database) is False, biosphere_excs
|
|
461
|
+
):
|
|
462
|
+
|
|
463
|
+
if exc["name"].lower() == "water":
|
|
464
|
+
exc["unit"] = "kilogram"
|
|
465
|
+
exc["amount"] *= 1000
|
|
466
|
+
|
|
467
|
+
u_type = get_simapro_uncertainty_type(
|
|
468
|
+
exc.get("uncertainty type")
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
if len(exc["categories"]) > 1:
|
|
472
|
+
sub_compartment = self.simapro_subcompartment[
|
|
473
|
+
exc["categories"][1]
|
|
474
|
+
]
|
|
475
|
+
else:
|
|
476
|
+
sub_compartment = ""
|
|
477
|
+
|
|
478
|
+
rows.append(
|
|
479
|
+
[
|
|
480
|
+
f"{self.simapro_biosphere.get(exc['name'], exc['name'])}",
|
|
481
|
+
sub_compartment,
|
|
482
|
+
self.simapro_units[exc["unit"]],
|
|
483
|
+
"{:.3E}".format(exc["amount"]),
|
|
484
|
+
u_type,
|
|
485
|
+
"{:.3E}".format(
|
|
486
|
+
convert_sd_to_sd2(exc.get("scale", 1), u_type)
|
|
487
|
+
),
|
|
488
|
+
"{:.3E}".format(exc.get("min", 0)),
|
|
489
|
+
"{:.3E}".format(exc.get("max", 0)),
|
|
490
|
+
exc.get("comment"),
|
|
491
|
+
]
|
|
492
|
+
)
|
|
493
|
+
exc["used"] = True
|
|
494
|
+
rows.append([])
|
|
495
|
+
|
|
496
|
+
if field == "Waste to treatment":
|
|
497
|
+
techno_excs = get_technosphere_exchanges(activity)
|
|
498
|
+
techno_excs = list(
|
|
499
|
+
filter(
|
|
500
|
+
lambda x: is_blacklisted(x, database) is False, techno_excs
|
|
501
|
+
)
|
|
502
|
+
)
|
|
503
|
+
techno_excs = check_exchanges_for_conversion(techno_excs, database)
|
|
504
|
+
|
|
505
|
+
for exc in filter(
|
|
506
|
+
lambda x: is_a_waste_treatment(x["name"], database=database)
|
|
507
|
+
is True,
|
|
508
|
+
techno_excs,
|
|
509
|
+
):
|
|
510
|
+
|
|
511
|
+
# In SimaPro, waste inputs are positive numbers
|
|
512
|
+
if exc["amount"] < 0:
|
|
513
|
+
exc["amount"] *= -1
|
|
514
|
+
|
|
515
|
+
exchange_name = format_exchange_name(
|
|
516
|
+
exc["name"],
|
|
517
|
+
exc["reference product"],
|
|
518
|
+
exc.get("location", "GLO"),
|
|
519
|
+
exc["unit"],
|
|
520
|
+
database,
|
|
521
|
+
)
|
|
522
|
+
|
|
523
|
+
u_type = get_simapro_uncertainty_type(
|
|
524
|
+
exc.get("uncertainty type")
|
|
525
|
+
)
|
|
526
|
+
|
|
527
|
+
rows.append(
|
|
528
|
+
[
|
|
529
|
+
f"{exchange_name}",
|
|
530
|
+
self.simapro_units[exc["unit"]],
|
|
531
|
+
"{:.3E}".format(exc["amount"]),
|
|
532
|
+
u_type,
|
|
533
|
+
"{:.3E}".format(
|
|
534
|
+
convert_sd_to_sd2(exc.get("scale", 1), u_type)
|
|
535
|
+
),
|
|
536
|
+
"{:.3E}".format(exc.get("min", 0)),
|
|
537
|
+
"{:.3E}".format(exc.get("max", 0)),
|
|
538
|
+
exc.get("comment"),
|
|
539
|
+
]
|
|
540
|
+
)
|
|
541
|
+
exc["used"] = True
|
|
542
|
+
|
|
543
|
+
rows.append([])
|
|
544
|
+
|
|
545
|
+
rows.append([])
|
|
546
|
+
|
|
547
|
+
# Add metadata: system descriptions and literature references
|
|
548
|
+
for field in (
|
|
549
|
+
"System description",
|
|
550
|
+
"Literature reference",
|
|
551
|
+
):
|
|
552
|
+
if field.lower() in self.metadata:
|
|
553
|
+
rows.extend([[field], []])
|
|
554
|
+
for key, val in self.metadata[field.lower()].items():
|
|
555
|
+
rows.extend(
|
|
556
|
+
[
|
|
557
|
+
[key],
|
|
558
|
+
[val],
|
|
559
|
+
[],
|
|
560
|
+
]
|
|
561
|
+
)
|
|
562
|
+
rows.append([])
|
|
563
|
+
rows.extend([["End"], []])
|
|
564
|
+
|
|
565
|
+
# check that all exchanges of all activities
|
|
566
|
+
# have been used
|
|
567
|
+
# print it in a prettytable
|
|
568
|
+
print_unused_exchanges(self.inventories)
|
|
569
|
+
|
|
570
|
+
return rows
|
|
571
|
+
|
|
572
|
+
def convert_to_simapro(
|
|
573
|
+
self, database: str = "ecoinvent", format: str = "csv"
|
|
574
|
+
) -> [str, list]:
|
|
575
|
+
"""Export the converted inventories.
|
|
576
|
+
|
|
577
|
+
The inventories are formatted using
|
|
578
|
+
:meth:`format_inventories_for_simapro` and either returned as raw data
|
|
579
|
+
or written to disk as a CSV file, depending on ``format``.
|
|
580
|
+
|
|
581
|
+
:param database: Database to use when resolving exchanges. Accepted
|
|
582
|
+
values are ``"ecoinvent"`` and ``"uvek"``.
|
|
583
|
+
:type database: str
|
|
584
|
+
:param format: Output mode. Use ``"data"`` to receive the converted
|
|
585
|
+
rows instead of writing a CSV file.
|
|
586
|
+
:type format: str
|
|
587
|
+
:return: The CSV filepath when ``format`` is ``"csv"`` or the raw
|
|
588
|
+
SimaPro data rows when ``format`` is ``"data"``.
|
|
589
|
+
:rtype: str | list[list[str]]
|
|
590
|
+
:raises ValueError: If an unsupported ``database`` value is supplied.
|
|
591
|
+
"""
|
|
592
|
+
|
|
593
|
+
if database not in ("ecoinvent", "uvek"):
|
|
594
|
+
raise ValueError("Database must be either `ecoinvent` or `uvek`")
|
|
595
|
+
|
|
596
|
+
data = self.format_inventories_for_simapro(database)
|
|
597
|
+
|
|
598
|
+
if format == "data":
|
|
599
|
+
return data
|
|
600
|
+
|
|
601
|
+
# check that export direct exists
|
|
602
|
+
# otherwise we create it
|
|
603
|
+
self.export_dir.mkdir(parents=True, exist_ok=True)
|
|
604
|
+
|
|
605
|
+
filepath = (
|
|
606
|
+
self.export_dir
|
|
607
|
+
/ f"simapro_{database}_{datetime.datetime.today().strftime('%d-%m-%Y')}.csv"
|
|
608
|
+
)
|
|
609
|
+
|
|
610
|
+
with open(filepath, "w", newline="", encoding="utf-8") as csvFile:
|
|
611
|
+
writer = csv.writer(csvFile, delimiter=";")
|
|
612
|
+
for row in data:
|
|
613
|
+
writer.writerow(row)
|
|
614
|
+
csvFile.close()
|
|
615
|
+
|
|
616
|
+
return f"Inventories export to: {filepath}"
|