Comments (4)
Can you provide an example? If I try
import pycopancore.data_model.master_data_model as D
from pycopancore import Variable
import pycopancore.models.example1 as M
model = M.Model()
c = M.Culture(environmental_friendliness_learning_rate=1, awareness_update_rate=1/D.weeks)
print(c.environmental_friendliness_learning_rate, c.awareness_update_rate)
then I correctly get
1 52.177499999999995
(both Variables have unit=D.years**-1
in the interface declaration)
from pycopancore.
I mean the interface declaration. If you choose e.g. unit=D.months**(-1)
it does not work. More specifically: the step timing does not work.
Code snippets:
meeting_rate = 1 / D.months
print(1*D.years + 1/meeting_rate)
The above correctly produces 1.0833333333333333 yr
,
however
Step("do meeting",
[B.Culture.worlds.individuals.engagement_level],
[next_meeting_time,
do_meeting
]
),
where
def next_meeting_time(self, t):
return t + 1/self.meeting_rate
produces meetings at 1.0
, 2.0
, and so on
Note that when defining in the run script
def next_meeting_time(t):
return t + 1/meeting_rate
print(next_meeting_time(1*D.years))
returns the correct time
from pycopancore.
OK I see. Here you have spotted a nasty one indeed.
What happens is this: For performance reasons, the values of Variables are stored as simple numbers in the individual entity attributes, to be interpreted in the unit that was listed in the interface. Also the current model time, t, is stored as a simple number, to be interpreted in the default time unit, years.
When a user provides a DimensionalQuantity object such as 1*D.years or 1/D.weeks as the initial value of a Variable, either as the default value in the interface or upon entity instantiation, then this dimensional quantity is converted into the Variable's unit and stored in the attribute. The same happens when setting a Variable's value later on via the Variable object's set_value
method and using a DimensionalQuantity as its argument.
However, when reading the Variable's value inside a method of the entity, or when using the time argument t that the runner used in its call to a method, the unit information is not used automatically because python just sees a number at that point and does not know it is actually meant as a dimensional quantity having a certain unit. So when adding to that purely numerical value some other DimensionalQuantity as in your example, the numerical value gets interpreted in the same unit as the DimensionalQuantity, in your case as weeks rather than years, causing the bug.
When you call the method from outside the runner with a DimensionalQuantity like 1*D.years, as in your example, then the addition is between two DimensionalQuantity objects of the same dimension (time) but different units, which works since the DimensionalQuantity class then automatically does the correct conversion.
The most convenient solution would be to store all values as DimensionalQuantities rather than as simple numbers, because this would not only prevent unit mix-ups of the kind you saw, but would also prevent invalid operations with quantities of different dimension (like adding a time to a length). But it would probably slow down simulations quite much.
An alternative would be to disable the choice of a unit when declaring a Variable and only enable the specification of a Dimension, and then store all supplied values in that Dimension's default unit. This would be a breaking change in that some interface code would become invalid and have to be fixed (by replacing the unit spec by a dimension spec and adjusting any provided numerical arguments, e.g. default, lower/upper bound, quantum, etc.).
An additional safety measure would be to automatically convert a DimensionalQuantity into its dimension's standard unit when it is added to a simple number.
These two fixes would prevent unit mix-ups of the kind you saw, but would not prevent dimension mix-ups like adding a time to a length.
What do you think?
from pycopancore.
I think it would make sense to under the hood always store each variable in a standard unit for each given dimension and have the calculations be made with pure numbers rather than DimensionalQuantities.
Being able to declare a unit in the interface in which input is given still makes sense, e.g. when you have variables working on the second and the year scale and you don't want to type units with every input, or exchange with other data formats such as JSON or YAML.
In this solution interfaces can stay the way they are and computation can stay as fast as it currently is.
To prevent dimension and unit mix-ups just the code could be checked once at initialization but of course not with every time step.
from pycopancore.
Related Issues (20)
- streamline documentation across branches HOT 1
- create status checks
- lpjml coupling HOT 2
- provide Culture.individuals
- Error message when not giving initial values HOT 1
- provide group entity HOT 1
- Possible solution to PYTHONPATH problem
- two culture setters for world
- review tutorial model configuration
- Adjust Templates and Tutorial for new group entity
- Improve process documentation
- provide way so save (adaptive) networks
- profile code
- provide best-practice in performance questions
- Give process taxa a UID
- patch Model.__init__ (taxa instantiation for mc runs)
- collections.MutableSet replaced by collections.abc.MutableSet
- consider Cython support?
- [Feature] Can produce ODD-compliant model (component) documentation
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from pycopancore.