Dealing with activity parameters with duplicate names in Brightway2 - brightway

Brightway2 allows parameterization at the activity level. These activity-level parameters need to be added to a group via
new_activity_parameters or add_to_group.
I'm struggling finding the best approach for dealing with the case where (1) calculations need to be done with activity-parameters from multiple activities and (2) parameters from the different activities can have the same parameter name (i.e. we may find "fuel_efficiency" in many activities).
act_params_data_A = {
'name': 'fuel_efficiency',
'database': 'db',
'code': 'A',
'amount': 0.5
}
act_params_data_B = {
'name': 'fuel_efficiency',
'database': 'db',
'code': 'B',
'amount': 0.9
}
Here are some options, and why they either straight-out don't work, why they seem sub-optimal or what I'm missing to make them work. I'm looking for some guidance.
Option 1: Add both activity parameters to the same group, overwrite=False (does NOT work)
parameters.new_activity_parameters(act_params_A, "some_group")
parameters.new_activity_parameters(act_params_B, "some_group", overwrite=False) #--> raises ValueError
Option 2: Add both activity parameters to the same group, overwrite=True (does NOT work)
parameters.new_activity_parameters(act_params_A, "some_group")
parameters.new_activity_parameters(act_params_B, "some_group", overwrite=True)
This overwrites act_params_A, so activity A will use 0.9 as value for the fuel_efficiency.
Option 3: Modify activity parameter names to make them unique, and then add to the same group
act_params_data_A['name'] = "{}_{}".format(
act_params_data_A['code'],
act_params_data_A['name']
) # New name is A_fuel_efficiency
act_params_data_B['name'] = "{}_{}".format(
act_params_data_B['code'],
act_params_data_B['name']
) # New name is B_fuel_efficiency
parameters.new_activity_parameters(act_params_A, "some_group")
parameters.new_activity_parameters(act_params_B, "some_group")
This would work, and the uniqueness of names is guaranteed since the uniqueness of codes is guaranteed. However, there is no guarantee that the codes are acceptable strings for parameter names (e.g. an activity can have a key=('db', 'some code'), and 'some code_fuel_efficiency`is not a valid parameter name). We could of course "clean" the activity code, but this could result in non-unique cleaned parameters.
Option 4: Each activity is sent to its own group
parameters.new_activity_parameters(act_params_A, "some_group")
parameters.new_activity_parameters(act_params_B, "other_group")
The problem is that I'm unsure how to then use these groups, especially how to pass these to a presamples ParameterizedBrightwayModel. We can of course create a super group, and make these activity-level groups dependencies, but dependencies (where the first encounter of a parameter name from a defined group order) and name-spaces (activity parameters exist within activities) are different things so I'm not sure if that would even help.
Have I missed anything?

Related

ArangoDB: Traversal condition on related document

Been stuck for days with this concern, trying to accomplish this:
See the provided picture.
The black is the start vertex. Trying to get:
1: All child parts OUTBOUND (from) the start vertex
2: Condition: The children MUST have the INBOUND edge"types" and the other end a document with a variable set to "true" and of the type "type".
3: When a document of type "part" fails to met up the requirements with INBOUND document of type "type" with a attribute to "true", it stops the expand for that path then and there.
4: The documents who failed isn't included in the result either.
5: Should be compatible with any depths.
6: No subqueries (if possible without).
Example of graph
With the given information, the data model seems questionable. Why are there true and false vertices instead of a boolean edge attribute per partScrew? Is there a reason why it is modeled like this?
Using this data model, I don't see how this would be possible without subqueries. The traversal down a path can be stopped early with PRUNE, but that does not support subqueries. That only leaves FILTER for post-filtering as option, but be careful, you need to check all vertices on the path and not just the emitted vertex whether it has an inbound false type.
Not sure if it works as expected in all cases, but here is what I came up with and the query result, which looks good to me:
LET startScrew = FIRST(FOR doc IN screw LIMIT 1 RETURN doc) // Screw A
FOR v,e,p IN 1..2 OUTBOUND startScrew partScrew
FILTER (
FOR v_id IN SHIFT(p.vertices[*]._id) // ignore start vertex
FOR v2 IN 1..1 INBOUND v_id types
RETURN v2.value
) NONE == false
RETURN {
path: CONCAT_SEPARATOR(" -- ", p.vertices[*].value)
}
path
Screw A -- Part D
Screw A -- Part E
Screw A -- Part E -- Part F
Dump with test data: https://gist.github.com/Simran-B/6bd9b154d1d1e2e74638caceff42c44f

Creating Node.js enum in code to match list of values in database

I have a list of valid values that I am storing in a data store. This list is about 20 items long now and will likely grow to around 100, maybe more.
I feel there are a variety of reasons it makes sense to store this in a data store rather than just storing in code. I want to be able to maintain the list and its metadata and make it accessible to other services, so it seems like a micro-service data store.
But in code, we want to make sure only values from the list are passed, and they can typically be hardcoded. So we would like to create an enum that can be used in code to ensure that valid values are passed.
I have created a simple node.js that can generate a JS file with the enum right from the data store. This could be regenerated anytime the file changes or maybe on a schedule. But sharing the enum file with any node.js applications that use it would not be trivial.
Has anyone done anything like this? Any reason why this would be a bad approach? Any feedback is welcome.
Piggy-backing off of this answer, which describes a way of creating an "enum" in JavaScript: you can grab the list of constants from your server (via an HTTP call) and then generate the enum in code, without the need for creating and loading a JavaScript source file.
Given that you have loaded your enumConstants from the back-end (here I hard-coded them):
const enumConstants = [
'FIRST',
'SECOND',
'THIRD'
];
const temp = {};
for (const constant of enumConstants) {
temp[constant] = constant;
}
const PlaceEnum = Object.freeze(temp);
console.log(PlaceEnum.FIRST);
// Or, in one line
const PlaceEnum2 = Object.freeze(enumConstants.reduce((o, c) => { o[c] = c; return o; }, {}));
console.log(PlaceEnum2.FIRST);
It is not ideal for code analysis or when using a smart editor, because the object is not explicitly defined and the editor will complain, but it will work.
Another approach is just to use an array and look for its members.
const members = ['first', 'second', 'third'...]
// then test for the members
members.indexOf('first') // 0
members.indexOf('third') // 2
members.indexOf('zero') // -1
members.indexOf('your_variable_to_test') // does it exist in the "enum"?
Any value that is >=0 will be a member of the list. -1 will not be a member. This doesn't "lock" the object like freeze (above) but I find it suffices for most of my similar scenarios.

gcloud datastore: Can I filter with IN or Contains operator?

I am a new bee with the Datastore gCloud. And I want to filter in an entity called Score all the scores that have relation with a list of companies. My entity is formed as follows:
{
    "company_id": 1,
    "score": 100,
}
I have several entities with different company IDs. I tried to filter using the query.add_filter command but got the error ValueError:
('Invalid expression: "IN"', 'Please use one of: =, <, <=,>,> =.')
The reason for the error is very clear to me, but I have not found anything in the documentation on how to run filters with IN or CONTAINS, in addition to types other than those listed in the above error message.
The filters operators you seek are not supported by the datastore. The only supported ones are listed in Filters:
The comparison operator can be any of the following:
Operator Meaning
EQUAL Equal to
LESS_THAN Less than
LESS_THAN_OR_EQUAL Less than or equal to
GREATER_THAN Greater than
GREATER_THAN_OR_EQUAL Greater than or equal to
Some of the client libraries may offer some equivalents, but with limitations. For example the standard environment GAE-specific ndb library (not usable in your context) offers such support. The example from The != and IN Operations can be useful as you can implement it in a similar manner in your code:
Similarly, the IN operation
property IN [value1, value2, ...]
which tests for membership in a list of possible values, is
implemented as
(property == value1) OR (property == value2) OR ...

couchDB sorting complex key

I have a couchDB database which has several different document "types" which all relate to a main "type".
In the common blog / post example, the main type is the blog post, and the others are comments (though there are 3 different types of comments.
All of the types have a date on them, however, I wish to sort blog posts by date, but return all of the data from the comments as well. I can write an emit which produces keys like so:
[date, postID, docTypeNumber]
where docTypeNumber is 1 for post and > 1 for the different comment document types.
e.g:
["2013-03-01", 101, 1]
[null, 101, 2]
[null, 101, 2]
[null, 101, 3]
["2013-03-02", 101, 1]
[null, 102, 2]
[null, 102, 3]
Of course, If I emit this, all the nulls get sorted together. Is there a way to ignore the nulls, and group them by the seccond item in the array, but sort them by the first if it is not null?
Or, do I have to get all the documents to record the post date in order for sort to work?
I do not want to use lists, they are way too slow and I'm dealing with a potentially large data set.
You can do this by using conditionals in your map function.
if(date != null) {
emit([date, postID, docTypeNumber]);
}
else {
emit([postID, docTypeNumber]);
}
I don't know if you want your array length to be variable or not. If not, you could add the sort variable first. The following snippet could work since date and postID presumably never have the same values.
if(date != null) {
sortValue = date;
}
else {
sortValue = postID;
}
emit(sortValue, date, postID, docTypeNumber);
Update: I thought about this a little more. In general, I make my views based on queries I want to perform. So I ask myself, what do I need to query? It seems that in your case, you might have two distinct queries here. If so, I suggest having two different views. There is a performance penalty to pay since you would run two views instead of one, but I doubt it is perceivable to the user. And it might take up more disk space. The benefit for you would be clearer and more explicit code.
It seems you want to sort all the data (both the post and the comments) with post's date. Since in your design comment document does not contain post date (just comment date) it is difficult with the view collation pattern. I suggest changing the database design to have blog post ID meaningful and contain the date, eg. concatenated date with author id. This way if you emit [doc._id, doc.type] from the post and [doc.post, doc.type] from the comment document you will have post and comments grouped and sorted by date.

Receiving reply from Redis ZRANGE

I currently have two sorted sets and I am trying to get all scores and members from one set and use it to remove members from the other set. The module that I am using is node_redis.
Right now I am trying to get the members and scores by calling client.zrange() and storing the reply in an array.
Am I correct in assuming the reply would be in array form? I realize the redis api says it returns a "Multi-bulk reply" but what does that mean exactly and how would I go about using it if it isn't an array?
I also have another question and that is can I use an array when using zadd()?
An example would be like this.
client.zadd(historyKey, scores, members, function(err, reply){});
Where scores and members are arrays.
EDIT:
I am working with receiving and parsing SNMP Traps. Basically I receive a trap and check its alarm type. The useful information in these traps are the alarm type and the full trap name. I check to see if the alarm is a 0,1, or 2.
If it's a 1, then I store it in my Current sorted set at the unix time I received it. If it's a 0 or 2 I know that type of alarm is done and that I need to remove all traps like it from the Current set and put them into the History set along with the one I just received.
In order to remove the traps from the Current and put them into the History I had to create a separate set for each individual trap in order to keep track of where they would be located in the Current set.
That is if I receive the trap "RGB Gamut Error( ----Bb )" at time 1346276537 and store it in Current, I also store the exact score and member in a separate set with key "IPAddress:RGB Gamut Error".
That way when I receive alarm type 0 or 2 with the name "RGB Gamut Error" I can just append the IP Address to the front of it, go do zrange on that set, then add to History and remove from Current. And lastly delete the "IPAddress:RGB Gamut Error" set so I can start fresh.
Sidenote: My members actually have two numbers added to the end in order to make each member unique and not overwrite each other. This is really there only purpose.
Ex: IPAdress::RGB Gamut Error( Rr--Bb ):5:46
Am I correct in assuming the reply would be in array form?
Yes, node_redis will give you the reply from a zrange as an array.
I also have another question and that is can I use an array when using zadd()? An example would be like this.
No. Before redis 2.4, you could only send one parameter at a time (so zadd key score member). Since redis 2.4, zadd (and many other commands) are variadic, i.e. they accept any number of parameters -- but not as an array. You still have to call it like this:
client.zadd(key, score1, member1, score2, member2, ..., function(err, reply){});
You could do some .apply trickery, but you would have to zip the scores and members arrays into one array first.
Update:
If you already have scores and members arrays, you could merge them into one array like this:
var scores = [1, 2, 3],
members = ['a', 'b', 'c'];
function merge (other) {
return function (result, current, index) {
result.push(current, other[index]);
return result;
}
}
var merged = scores.reduce(merge(members), []);
// Now merged = [1, 'a', 2, 'b', 3, 'c'];
var args = [key].concat(merged).concat(function(err, reply){});
client.zadd.apply(client, args);

Resources