AWARE method in ecoinvent through brightway2 - brightway

i'm trying to extract all water inputs to several processes using brightway or ab, but i'm having troubles getting those values from the inventory_matrix. I need to get quantity of water consumed and origin of the water (surface, well, unspecified, tap water) along with its geography. mI'm using ecoinvent 3.7.1
One way i thought i could do that is create an impact assessment method with CFs for those compartments (each of those will be 1s), then apply it to the processes and analyse the elementary flows contributions.
I'm not sure though i can get the geography like this.
EDITED MOST OF THE QUESTION FOR CLARITY
Seems like i was trying to reinvent the wheel! My goal is to implement AWARE method and apply it to quite a few processes. the best result would be to use AWARE through activity-browser so i can use all of its functionalities which are very time-saving for me.
i just saw that there is brightway2-regional and bw2_aware that implement the aforementioned method.
So i'm now trying to install the packages in my brightway2 conda environment.
Managed to get bw2regional through conda but i cant manage to install bw2_aware if not through pip.
managed to install bw2_aware by using the wheel file and pip install --no-deps and then tweaking a line in the source code for fiona import, now i'm getting errors when running
bwr.bw2regionalsetup()
bw2_aware.import_aware()
SSLError: HTTPSConnectionPool(host='pandarus.brightwaylca.org', port=443): Max retries exceeded with url: / (Caused by SSLError(CertificateError("hostname 'pandarus.brightwaylca.org' doesn't match either of '*.parkingcrew.net', 'parkingcrew.net'",),))
Now i'm trying to understand if i can apply this to ecoinvent, and how. i'm really unsure if i can add the different geographies to the elementary flows in the database, so that i can correctly calculte aware in a lca.
I already saw that importing AWARE allows to choose it as a impact cathegory in activity-browser, though i cannot see the geographies in the CFS shown in the Charaterization Factors tab.
So i then tried to calculate an LCA with AB using AWARE method and 2 sample processes:
diesel, burned in agricultural machinery | diesel, burned in agricultural machinery | GLO | megajoule | ECOINVENT3.7.1
electricity, high voltage | market for electricity, high voltage | IT | kilowatt hour | ECOINVENT3.7.1
and i get this result (first is Agricultural, the other is non Agricultural):
diesel, burned in agricultural machinery | GLO
0.014757994762941706 0.00654978730728395
market for electricity, high voltage | IT 0.285207979534988 0.12657895834095712
I wonder if this is correct.

Your intuition is correct - constructing an LCIA method is an easy way to do this. This is because there are unspoken assumptions behind these flows - they will be mostly positive numbers, but some represent consumption, while others represent release.
Here is an example using Brightway 2.5, it would need to be adapted for version 2:
import bw2data as bd
import bw2calc as bc
import numpy as np
bd.projects.set_current("ecoinvent 3.7.1")
ecoinvent = bd.Database("ecoinvent 3.7.1")
beet = ecoinvent.search("beet")[1]
water_method = bd.Method(("Water", "raw"))
water_method.register()
water_method.write([(x, -1 if x['categories'][0] == 'natural resource' else 1)
for x in bd.Database("biosphere3")
if x['name'].startswith('Water')])
demand, data_objs, _ = bd.prepare_lca_inputs(demand={beet: 1}, method=("Water", "raw"))
lca = bc.LCA(demand=demand, data_objs=data_objs)
lca.lci()
lca.lcia()
coo = lca.characterized_inventory.tocoo()
results = sorted(zip(np.abs(coo.data), coo.data, coo.row, coo.col), reverse=True)
for a, b, c, d in results[:10]:
print("{:.6f}\t{}\n\t\t{}".format(
float(b),
bd.get_activity(lca.dicts.biosphere.reversed[c]),
bd.get_activity(lca.dicts.activity.reversed[d])
))
With the result:
0.009945 'Water' (cubic meter, None, ('water',))
'electricity production, hydro, run-of-river' (kilowatt hour, CH, None)
-0.009945 'Water, turbine use, unspecified natural origin' (cubic meter, None, ('natural resource', 'in water'))
'electricity production, hydro, run-of-river' (kilowatt hour, CH, None)
0.009514 'Water' (cubic meter, None, ('water',))
'electricity production, hydro, run-of-river' (kilowatt hour, RoW, None)
-0.009514 'Water, turbine use, unspecified natural origin' (cubic meter, None, ('natural resource', 'in water'))
'electricity production, hydro, run-of-river' (kilowatt hour, RoW, None)
0.007264 'Water' (cubic meter, None, ('water',))
'electricity production, hydro, run-of-river' (kilowatt hour, FR, None)
-0.007264 'Water, turbine use, unspecified natural origin' (cubic meter, None, ('natural resource', 'in water'))
'electricity production, hydro, run-of-river' (kilowatt hour, FR, None)
-0.003371 'Water, river' (cubic meter, None, ('natural resource', 'in water'))
'irrigation, sprinkler' (cubic meter, CH, None)
0.003069 'Water' (cubic meter, None, ('water', 'ground-'))
'sugar beet production' (kilogram, CH, None)
0.001935 'Water' (cubic meter, None, ('air',))
'sugar beet production' (kilogram, CH, None)
0.001440 'Water' (cubic meter, None, ('water',))
'electricity production, hydro, run-of-river' (kilowatt hour, CN-SC, None)

There isn't a way to use regionalized calculations in the activity browser, and the AWARE method (incorrectly) relies on an external web service which is not strictly necessary. So the short answer is that this isn't possible right now, but as you are the second person to ask about this in a week, we need to get it working ASAP.

Related

Confusion About Implementing LeafSystem With Vector Output Port Correctly

I'm a student teaching myself Drake, specifically pydrake with Dr. Russ Tedrake's excellent Underactuated Robotics course. I am trying to write a combined energy shaping and lqr controller for keeping a cartpole system balanced upright. I based the diagram on the cartpole example found in Chapter 3 of Underactuated Robotics [http://underactuated.mit.edu/acrobot.html], and the SwingUpAndBalanceController on Chapter 2: [http://underactuated.mit.edu/pend.html].
I have found that due to my use of the cart_pole.sdf model I have to create an abstract input port due receive FramePoseVector from the cart_pole.get_output_port(0). From there I know that I have to create a control signal output of type BasicVector to feed into a Saturation block before feeding into the cartpole's actuation port.
The problem I'm encountering right now is that I'm not sure how to get the system's current state data in the DeclareVectorOutputPort's callback function. I was under the assumption I would use the LeafContext parameter in the callback function, OutputControlSignal, obtaining the BasicVector continuous state vector. However, this resulting vector, x_bar is always NaN. Out of desperation (and testing to make sure the rest of my program worked) I set x_bar to the controller's initialization cart_pole_context and have found that the simulation runs with a control signal of 0.0 (as expected). I can also set output to 100 and the cartpole simulation just flies off into endless space (as expected).
TL;DR: What is the proper way to obtain the continuous state vector in a custom controller extending LeafSystem with a DeclareVectorOutputPort?
Thank you for any help! I really appreciate it :) I've been teaching myself so it's been a little arduous haha.
# Combined Energy Shaping (SwingUp) and LQR (Balance) Controller
# with a simple state machine
class SwingUpAndBalanceController(LeafSystem):
def __init__(self, cart_pole, cart_pole_context, input_i, ouput_i, Q, R, x_star):
LeafSystem.__init__(self)
self.DeclareAbstractInputPort("state_input", AbstractValue.Make(FramePoseVector()))
self.DeclareVectorOutputPort("control_signal", BasicVector(1),
self.OutputControlSignal)
(self.K, self.S) = BalancingLQRCtrlr(cart_pole, cart_pole_context,
input_i, ouput_i, Q, R, x_star).get_LQR_matrices()
(self.A, self.B, self.C, self.D) = BalancingLQRCtrlr(cart_pole, cart_pole_context,
input_i, ouput_i,
Q, R, x_star).get_lin_matrices()
self.energy_shaping = EnergyShapingCtrlr(cart_pole, x_star)
self.energy_shaping_context = self.energy_shaping.CreateDefaultContext()
self.cart_pole_context = cart_pole_context
def OutputControlSignal(self, context, output):
#xbar = copy(self.cart_pole_context.get_continuous_state_vector())
xbar = copy(context.get_continuous_state_vector())
xbar_ = np.array([xbar[0], xbar[1], xbar[2], xbar[3]])
xbar_[1] = wrap_to(xbar_[1], 0, 2.0*np.pi) - np.pi
# If x'Sx <= 2, then use LQR ctrlr. Cost-to-go J_star = x^T * S * x
threshold = np.array([2.0])
if (xbar_.dot(self.S.dot(xbar_)) < 2.0):
#output[:] = -self.K.dot(xbar_) # u = -Kx
output.set_value(-self.K.dot(xbar_))
else:
self.energy_shaping.get_input_port(0).FixValue(self.energy_shaping_context,
self.cart_pole_context.get_continuous_state_vector())
output_val = self.energy_shaping.get_output_port(0).Eval(self.energy_shaping_context)
output.set_value(output_val)
print(output)
Here are two things that might help:
If you want to get the state of the cart-pole from MultibodyPlant, you probably want to be connecting to the continuous_state output port, which gives you a normal vector instead of the abstract-type FramePoseVector. In that case, your call to get_input_port().Eval(context) should work just fine.
If you do really want to read the FramePoseVector, then you have to evaluate the input port slightly differently. You can find an example of that here.

PACF function in statsmodels.tsa.stattools gives numbers greater than 1 when using ywunbiased?

I have a dataframe which is of length 177 and I want to calculate and plot the partial auto-correlation function (PACF).
I have the data imported etc and I do:
from statsmodels.tsa.stattools import pacf
ys = pacf(data[key][array].diff(1).dropna(), alpha=0.05, nlags=176, method="ywunbiased")
xs = range(lags+1)
plt.figure()
plt.scatter(xs,ys[0])
plt.grid()
plt.vlines(xs, 0, ys[0])
plt.plot(ys[1])
The method used results in numbers greater than 1 for very long lags (90ish) which is incorrect and I get a RuntimeWarning: invalid value encountered in sqrtreturn rho, np.sqrt(sigmasq) but since I can't see their source code I don't know what this means.
To be honest, when I search for PACF, all the examples only carry out PACF up to 40 lags or 60 or so and they never have any significant PACF after lag=2 and so I couldn't compare to other examples either.
But when I use:
method="ols"
# or
method="ywmle"
the numbers are corrected. So it must be the algo they use to solve it.
I tried importing inspect and getsource method but its useless it just shows that it uses another package and I can't find that.
If you also know where the problem arises from, I would really appreciate the help.
For your reference, the values for data[key][array] are:
[1131.130005, 1144.939941, 1126.209961, 1107.300049, 1120.680054, 1140.839966, 1101.719971, 1104.23999, 1114.579956, 1130.199951, 1173.819946, 1211.920044, 1181.27002, 1203.599976, 1180.589966, 1156.849976, 1191.5, 1191.329956, 1234.180054, 1220.329956, 1228.810059, 1207.01001, 1249.47998, 1248.290039, 1280.079956, 1280.660034, 1294.869995, 1310.609985, 1270.089966, 1270.199951, 1276.660034, 1303.819946, 1335.849976, 1377.939941, 1400.630005, 1418.300049, 1438.23999, 1406.819946, 1420.859985, 1482.369995, 1530.619995, 1503.349976, 1455.27002, 1473.98999, 1526.75, 1549.380005, 1481.140015, 1468.359985, 1378.550049, 1330.630005, 1322.699951, 1385.589966, 1400.380005, 1280.0, 1267.380005, 1282.829956, 1166.359985, 968.75, 896.23999, 903.25, 825.880005, 735.090027, 797.869995, 872.8099980000001, 919.1400150000001, 919.320007, 987.4799800000001, 1020.6199949999999, 1057.079956, 1036.189941, 1095.630005, 1115.099976, 1073.869995, 1104.48999, 1169.430054, 1186.689941, 1089.410034, 1030.709961, 1101.599976, 1049.329956, 1141.199951, 1183.26001, 1180.550049, 1257.640015, 1286.119995, 1327.219971, 1325.829956, 1363.609985, 1345.199951, 1320.640015, 1292.280029, 1218.890015, 1131.420044, 1253.300049, 1246.959961, 1257.599976, 1312.410034, 1365.680054, 1408.469971, 1397.910034, 1310.329956, 1362.160034, 1379.319946, 1406.579956, 1440.670044, 1412.160034, 1416.180054, 1426.189941, 1498.109985, 1514.680054, 1569.189941, 1597.569946, 1630.73999, 1606.280029, 1685.72998, 1632.969971, 1681.550049, 1756.540039, 1805.810059, 1848.359985, 1782.589966, 1859.449951, 1872.339966, 1883.949951, 1923.569946, 1960.22998, 1930.6700440000002, 2003.369995, 1972.290039, 2018.050049, 2067.560059, 2058.899902, 1994.9899899999998, 2104.5, 2067.889893, 2085.51001, 2107.389893, 2063.110107, 2103.840088, 1972.180054, 1920.030029, 2079.360107, 2080.409912, 2043.939941, 1940.2399899999998, 1932.22998, 2059.73999, 2065.300049, 2096.949951, 2098.860107, 2173.600098, 2170.949951, 2168.27002, 2126.149902, 2198.810059, 2238.830078, 2278.8701170000004, 2363.639893, 2362.719971, 2384.199951, 2411.800049, 2423.409912, 2470.300049, 2471.649902, 2519.360107, 2575.26001, 2584.840088, 2673.610107, 2823.810059, 2713.830078, 2640.8701170000004, 2648.050049, 2705.27002, 2718.3701170000004, 2816.290039, 2901.52002, 2913.97998]
Your time series is pretty clearly not stationary, so that Yule-Walker assumptions are violated.
More generally, PACF is usually appropriate with stationary time series. You might difference your data first, before considering the partial autocorrelations.

how to paramaterise an existing exchange with brightway

I want to paramaterize exchanges of an existing brightway activity. in the example I've found the formula is defined for a new_exchange, can we do it for an existing one?
a practical example could be to redefine the fuel consumption as function of higher heating value and efficiency.
ex=[act for act in bw.Database('ei_34con') if 'natural gas' in act['name']
and 'condensing' in act['name']
and 'CH' in act['location']][0].copy()
ng_flow=[f for f in ex.technosphere() if ('natural gas' in f['name'])][0]
act_data=[{'name':'eff',
'database':ex['database'],
'code':ex['code'],
'amount':0.95,
'unit':''},
{'name':'HHV',
'database':ex['database'],
'code':ex['code'],
'amount':37,
'unit':'MJ/m3'}]
bw.parameters.new_activity_parameters(act_data, "my group")
I naively tried
ng_flow['formula']='1/eff/HHV'
bw.parameters.add_exchanges_to_group("my group", ex)
ActivityParameter.recalculate_exchanges("my group")
but parameters did not update the amount of the exchange.
You were quite close.
I reran your code and the line
bw.parameters.add_exchanges_to_group("my group", ex)
returns 0. This means no parameters were added.
However, if I save the exchange first:
ng_flow.save()
bw.parameters.add_exchanges_to_group("my group", ex)
returns 1, and
for exc in ex.technosphere():
if "natural gas" in exc['name']:
print(exc.amount, exc.input, exc.output)
Prints
0.028449502133712657 'market for natural gas, low pressure' (cubic meter, CH, None) 'heat production, natural gas, at boiler condensing modulating <100kW' (megajoule, CH, None)
Note that ng_flow.as_dict() does not show the updated value.

'location' filter on database.search filtering everything

I have imported the ecoinvent database as ei
The search function works quite well:
In[0] eidb.search("glass",
filter = {'name':'green',
'product':'packaging'
}
)
Excluding 296 filtered results
Out[0]:
['packaging glass production, green' (kilogram, RER w/o CH+DE, None),
'packaging glass production, green' (kilogram, DE, None),
'packaging glass production, green' (kilogram, RoW, None),
'packaging glass production, green' (kilogram, CH, None),
'packaging glass production, green, without cullet' (kilogram, GLO, None),
'market for packaging glass, green' (kilogram, GLO, None)]
This is exactly as one would hope.
However, filtering on 'location' does not work so well:
In[1] eidb.search("glass",
filter = {'location':'DE',
}
)
Excluding 304 filtered results
Out[1]: []
According to the above result, I should have at least two results.
'location' is definitely an accepted filter, and DE is definitely one of the locations (e.g. eidb.get('d2db85e14baf9e47bdbb824797420f08').get('location') returns DE).
I observe this anytime location is used as filter, e.g. eidb.search('*', filter = {'location':'CA-QC'}) returns an empty list.
Why?
I have no idea why this is occurring, but you can get the behaviour you are looking for by putting the location code in lowercase:
In [1]: db.search("glass", filter={"location": "de"})
Excluding 103 filtered results
Out[1]:
['glass tube plant' (unit, DE, ['glass', 'construction']),
'glass tube, borosilicate, at plant' (kilogram, DE, ['glass', 'construction']),
'packaging glass, white, at plant' (kilogram, DE, ['glass', 'packaging']),
'packaging glass, brown, at plant' (kilogram, DE, ['glass', 'packaging']),
'packaging glass, green, at plant' (kilogram, DE, ['glass', 'packaging']),
'solar collector glass tube, with silver mirror, at plant' (kilogram, DE, ['glass', 'construction']),
'photovoltaic laminate, CdTe, at plant' (square meter, DE, ['photovoltaic', 'production of components'])]
Please file this as a bug for bw2data.
Probably you have already noticed, but for the case of Quebec, using just the final part would work (e.g. eidb.search('*', filter = {'location':'qc'})). I've checked and in ecoinvent there are no regions with the location code QC, so there is no risk of including activities from other regions.
The problem does not seems to be only with uppercase and punctuation characters
ei.search('photovoltaic laminate, CdTe',
filter={"location": "US"}
)
Excluding 7 filtered results
[]
P.S: weird but in this case filter={"location": "DE"} find the correct dataset also with uppercase

Are eco-indicator endpoints reported in points or millipoints

How do I check if impacts are reported in—for example using 'eco-indicator 99, (H,A)', 'ecosystem quality', 'total'—in milli-points or points.
Metadata is stored in methods, so you should be able to do the following:
In [1]: methods[('eco-indicator 99, (H,A)', 'total', 'total')]['unit']
Out[1]: 'points'
You can also see complete method metadata:
In [1]: methods[('eco-indicator 99, (H,A)', 'total', 'total')]
Out[1]:
{'abbreviation': 'eco-indicator-99-hatt.418ee316e1a7611c9135b9abe7b490e7',
'description': 'Implementation of the impact assessment method with the normalized and weighted damage factor. Weights (30% human health, 50% ecosystem quality, 20% resources) and normalization for Egalitarian perspective. Correction of factors for nickel and chromium emissions and nickel and zinc resource. Own assessment for new land use categories.',
'filename': 'LCIA implementation v3.1 2014_08_13.xlsx',
'num_cfs': 1285,
'unit': 'points'}

Resources