Open ezio-melotti opened 3 years ago
Closed by mistake
These additional items are from Kai's conversation with Ray Wheeler on 22-Sept:
(original:) a) plant start/harvest staggering^ b) invoke random variation (entropy engine)^ c) human routine vs energy consumption and sleep d) a correlation between light duration and plant growth
^Also mentioned in https://github.com/overthesun/simoc/issues/105 (Phase V meta-issue).
I think this can be managed by the EnclosedAgent class.
Here is EnclosedAgent.step(): https://github.com/overthesun/simoc/blob/7dc4f780d4a87c6305629b5763de64303ddc068e/simoc_server/agent_model/agents/core.py#L178-L195
One way is to add a parameter stagger
characteristic in agent_desc for each agent next to lifetime
, and in EncloseAgent.step() do something like:
if self.stagger > 0:
self.stagger -= time_delta
// skip GeneralAgent.step()
if self.grown and not self.reproduce:
self.destroy()
else:
return // proceed to GeneralAgent.step()
From meeting minutes 09/22a, Ezio proposed 3 conceptual levels of entropy:
1) Entropy introduces random fluctuations in currency exchange 2) Mechanical system leaks: some leaks are lost to the exterior; some internal and accounted for 3) Total systems failure (e.g. airlock failure, plant demise, meteorite impact); game play
Ezio suggests that not all agents should be engaged at the same level of entropy, such that a lemon might be harvested as considerably smaller or larger, but the CO2 scrubber should not fluctuate at a much lower rate. So maybe we encode in each agent description an upper and lower boundary, or an additional, fixed variable that mitigates the entropy function. // .. // I think we should have:
- per-agent/per-connection entropy boundaries
- customizable default boundaries (e.g. ±5%)
- a bool value to turn off the entropy engine
If the entropy engine is on, and an agent/connection has specific entropy boundaries, they will be used, if they don't, the default boundaries will be used. If the entropy engine is off, no changes will be applied.
The backend appears to support 'noise' for both daily_ and lifetime_growth. It's input as a boolean value in the agentdesc, and given a default value of 10 in all the `get[...]_curvefunctions in
growth_func.py`.
First step (currently working on) is verifying that this existing function works, and considering if/how it plays into the above plan.
As I understand this would reflect how
I think these can use daily_growth_function
s, similar to solar. Solar uses the switch function, which is calculated as a normal dist. https://github.com/overthesun/simoc/blob/7dc4f780d4a87c6305629b5763de64303ddc068e/simoc_server/agent_model/agents/growth_func.py#L249-L283
We could add new functions, for example get_human_activity_curve
or get_meal_curve
, and use them in the relevant input/output fields.
per Kai's comment in the original email:
the code is already there but working in reverse--if the light is reduced the plant suffers. We can change this to be a linear function of light and plant growth.
PR #149 was a first step of the agent redesign which:
connections.json
, which is used to generate the connections programmatically instead of hard-coded. Example connection:
{
"from": "water_storage.h2o_potb",
"to": "human_agent.h2o_potb"
},
agent_desc.json
. All connections are assumed to be between an agent (class GeneralAgent) and a storage (class StorageAgent), and there is only 1 possible StorageAgent for each currency.inputs
and outputs
. If the input type is h2o_potb
, it will look look for the connection where the to:
field is human_agent.h2o_potb
, and append the target from:
from to agent.selected_storage.in.h2o_potb = []
.High-level objectives are:
crew_habitat_[size]
, rather than air_storage
atmo_co2
can be in crew_habitat_[size]
OR greenhouse_[size]
scuba_tank
s storing a backup for the habitat atmosphere, and a second group of 3 storing a backup for the greenhouse atmosphere. In this case, each 'group of 3' functions as a single (larger) agent, but those groups should have different connections and thresholds. To be clear, we don't have this functionality currently.The rough plan is to combine GeneralAgent and StorageAgent into a single class. Some considerations that should be addressed before proceeding:
There are basically 2 ways to 'scale-up' an agent:
StorageAgents use multiple instances of the same agent. In front_end_routes.convert_config()
, if the starting balance for currency is higher than the StorageAgent's capacity, a new instance is created. GeneralAgents have a separate connection to each instance, and inputs/outputs are split evenly between instances.
https://github.com/overthesun/simoc/blob/7dc4f780d4a87c6305629b5763de64303ddc068e/sample_game_config.json#L146-L155
GeneralAgents use a single instance with an amount
, and multiply inputs/output values by the current amount. This amount is incremented down by the deprive function. Agents could use multiple instances, but SINGLE_AGENT
is always set to 1
(see frontend/src/store/modules/wizard
line 249).
https://github.com/overthesun/simoc/blob/7dc4f780d4a87c6305629b5763de64303ddc068e/simoc_server/agent_model/agent_model.py#L775-L793
It seems that StorageAgents could use the second approach (amounts) to achieve the same functionality, and therefore we could eliminate instances altogether. ...convert_config()
would increase the amount of a storage rather than create a new instance, and 'capacity' would be multiplied by the amount. This reduces complexity, and means that connections.json
doesn't specify an instance, but it makes it doesn't allow different instances to function independently (per the scuba_tank
item above).
In two areas particularly:
crew_habitat_[size]
(small, medium, large and sam) has to specify a capacity for each atmo_[gas]
(o2, co2, n2, ch4, h2 and h2o). These fields are in agent_desc.json
connections.json
.These could be specified at some 'higher level'. We already use 'classes' in the agent_desc: all the crew_habitat_[size]
are part of structures
, and plants are part of plants
. We could add class attributes somewhere which are used, unless specified explicitly:
atmo_[gas]
programmatically based on the specified volume.Alternatively we could add 'prototypes' with the attributes that apply to all, and add e.g. prototype: plant
attribute to all the plants in the agent_desc.
Suppose humans connect to habitat and plants connect to greenhouse. If habitat/greenhouse are isolated, this works perfectly, and eclss agents (e.g. co2_removal_sawd
can transfer gasses between the two. However if they're not isolated, we would need to either:
This is a list of other things we discussed that are more or less related to the ABM. Some of these ideas are still half-baked and not well-defined yet, or are features we might want to add further down the line. They are no in no specific order (even though I tried to discuss related items close to each other).
Right now the agents are either on/off, so e.g. the ECLSS runs at full capacity if the CO2 goes above a certain threshold and turns off completely if it falls back below the threshold. We might want to have a way to e.g. run at half capacity.
This came up while discussing the "door" agent that should exchange air from the greenhouse and the crew quarters: currently it could either be open or close, but not half open. A workaround for this is having it open and close at alternating steps.
We might want to trigger deprivation only if a combination of events occur. This came up while discussing pressure combined with O2 levels (even if apparently we won't need compound deprivation for this). Another example might be in a situation where both rations and harvested plants run out: the deprivation shouldn't trigger when only one of the two runs out (unless we combined as discussed in the first message, in the grouping section).
Related: should the deprivation be calculated on the internal storage instead/in addition to the inputs? E.g. if there is no water left, but plenty of watermelons, can the human survive by eating watermelons without drinking water and without dying of dehydration?
Currently the air storage has separate "sub-storages" for O2, CO2, etc., but in reality these are mixed and share the same volume. Something similar might also apply to the food storage, where we might have a "shelf" with a certain volume, and we could fill it with different kinds of harvested plants that share the same space.
This is different from e.g. water storages, where each type of water has to be isolated by the others. How can we represent this distinction? How does pressure affects this in case of the air storage?
We should track habitat pressure.
Currently we are using names like atmo_co2
, h2o_potb
, etc.. These are useful when you need a single label to identify unequivocally a certain currency in a certain context, but it makes it more difficult to do other things.
With all agents becoming storages, the currencies will either be inside an agent or inputs/output of an agent. We could use a naming scheme like agent_name.currency_name
and perhaps agent_name.[in/out].currency_name
for connections. For example, atmo_co2
will become crew_quarters.co2
, and the humans will exhale human_agent.out.co2
. T
There are different ways to look at the content of a storage. For example, in the air storage we might have a certain amount of O2 and CO2. We might also represent this as a certain amount of carbon and oxygen atoms (the elemental validation might look at this representation). For the humans, we could keep track of how much H2O they drank and how much hydrogen and carbon there is in the human. We might also want to have a different view for macronutrients or calories.
Each view can provide a different breakdown of some aspect of the content of the storage.
We also want to track calories, and this applies to both food and machines (since they produce heat).
Each agent in the agent_desc.json
might have a different entropy level. This could apply to all values or just to some. For example some plants might grow twice as big as other plants of the same type, but solar panels might be only slightly more or less efficient that other similar panels.
The value could be expressed as a pair of values, indicating min and max variation, with 1
as "no variation". For example a pair like [0.8, 1.2]
indicates a possible variation of ±20%, [0.95, 1]
could indicate that up to 5% could be lost in a leak, but no more than 100% could be transferred.
The entropy can be applied both as an initial multiplier when the agent is created, and for each exchange. For example we could have a really good seed that will produce a plant twice as big as the others, but each exchange will also be subject to some amount of entropy. The formula will look something like base_value * fixed_agent_entropy * variable_agent_entropy
.
The seed could have an initial entropy between [0.1, 2.5]
and 2
might be the random initial value, and then the inputs/output might be in range [0.8, 1.2]
. If the plant normally draws 3g of CO2 for each step as a base value, this seed might draw 3g * 2 * 0.86 == 5.16g
.
When to agents are connected, sometimes an agent produces a certain amount as output for each step and "pushes" it out, whereas other times it contains a certain amount (as storage), and part of it gets pulled. For example, a human exhales a certain amount of CO2 as output, and the air_storage can provide a certain amount of CO2 as output for the plants. In the first case, the human is pushing out the CO2, in the second the plants are pulling out the CO2 from the air_storage.
This might also affect how entropy work. For example a plant takes CO2, H2O, nutrients, and light as inputs. For the CO2 and nutrients, it could pull how much it wants (assuming there is enough), but the H2O and light are provided in fixed amounts. The entropy shouldn't be able to determine e.g. how much light the plant will "pull" (in theory they could pull less, but not more), but it can determine how much light the lamps will "push" (less or more). This issue might be solved by setting an entropy of e.g. [0.9,1.1]
for lamps.out.light
and an entropy of e.g. [0.95, 1]
for plant.in.light
.
We could have a series of events that happen randomly, e.g.: sand storms, solar flares/storms, equipment failure, diseases, accidents, meteorite strikes, etc. Each of these event have a certain (very low) probability to happen at each step. Each even will also have a severity that will tell how serious the consequence of the event might be (as a range), and possible a duration/recovery time before the effects disappear (also a range).
We should figure out a "wellness index" for humans, that represents how well they feel based on the amount of food/water/sleep/work they had/did.
A similar concept can be applied to other agents as well, including machines. The baseline for the index could degrade as the agents age, and might also be subject to random fluctuations caused by external factors (e.g. humans not getting enough food/water/sleep, being overworked, etc.).
If we take the Coronavirus as an example, there is a certain probability the event will happen and the human will get infected. This will be affected and will affect the wellness index based on the severity of the infection. For example, an underfed and overworked human might have a lower wellness index (they will be weak), so once they gets infected they might need a longer recovery time. During this time, the wellness index will be further lowered. Another human might be struck with a lower severity and recover much quickly.
For a sand storm, the severity might affect how many/how much the solar panels will be covered in sand, and the duration how many hours will pass before the sand will go away.
The way the event affect the agent might also be described as a function (e.g. e.g. the sand on the panels might decrease linearly, whereas an infection might start mild, get worse, then mild again before disappearing).
From the meeting minutes 2021 10/17:
This issue lists possible changes/improvements to the ABM, that will solve some of the issues we had in the past and make SIMOC more flexible:
Agents and Storages
Currently we have agents that look like black boxes that get some inputs and produce some outputs at every step:
Then we have storages that are boxes that contain some currency:
Even though they both have inputs and outputs, there are currently 3 major differences between agents and storages:
Active means that they seek and pull inputs and push out outputs; passive that inputs and output are pushed in and pulled out by other agents. Performing transformations means that the inputs are processed to produce different outputs.
Note: in the diagram I'm using
--xxx-->|agent|
to indicate an active input (the agent pulls in the input), and>--xxx--|storage|
to indicate a passive input (the input is pushed into the storage). Similarly|agent|>--xxx--
is an active output (pushed out), and|agent|--xxx-->
is a passive output (pulled out by an agent).Note: technically not all agents have both inputs and outputs: we also have sources (agents that only produce outputs "without" input, e.g. solar panels) and sinks (agents that only take inputs "without" output, e.g. the CO2 scrubber).
Agents as storages
The first change that I propose is to have the agents act as storages too:
After this change, agents and storages wil have 2 similarities and 2 differences: They will both:
But:
Note: the transformation doesn't need to be defined accurately at a chemical level -- it is enough that at each step a certain amount is removed by each of the input storages (the boxes inside the human on the left) and a certain amount is added to the output storages (the ones on the right). The elemental validation will take care of making sure the amounts match.
This said, I'm not sure what the best way to think about this would be:
All agents are storages (or vice versa)
Unifiying agents and storages (at least at some level) allows us to solve several problems:
agent_desc.json
, and specify their characteristics (e.g. battery capacity)Connections
Problems:
Proposed solution:
.json
fileGrouping
Problem:
food_ration
andbiomass_edible
can both be used to sustain humans, orenergy_wind
andenergy_solar
can both be used to power up an ECLSS).Proposed solutions:
biomass_edible
should be used before thefood_rations
). Similarly we could store different currencies in a battery (e.g.energy_wind
,energy_solar
, etc.), but group and expose only one (e.g.energy_kwh
).biomass_edible
from the storage, orfood
if it doesn't matter.food_ration
andbiomass_edible
) and define the priority in the human agentinputs
section.Priorities
Problem:
Depending on the model, there are different kinds of priorities:
biomass_edible
beforeration
(in a non-grouping model)biomass_edible
overfood_ration
while providingfood
Since the exchanges happen between different agents, they might have different needs and priorities. For example a food storage might want to prioritize the use of
biomass_edible
, but an agent might want to getfood_ration
(this is solved if the grouping exposes bothfood
and the individualfood_ration
andbiomass_edible
).Proposed solution:
.json
, overridable from the config wizardConclusions
There are still several things that should be determined/clarified, and we should also verify if this model is compatible with the libraries that we are using (e.g. defining priorities, tracking internal storages, etc.). I think several -- if not all -- of these changes can be done incrementally, without having to rewrite everything from scratch.
Notes: ¹ Storages and their connections are hardcoded here: https://github.com/overthesun/simoc/blob/9131917125aba96d9d8e4b998cdf387b652e7ab2/simoc_server/front_end_routes.py#L183-L227 ² If all agents become storages, the connections will no longer be between agents and storages but just between agents