-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support multi-letter elements, make adding new elements easier. #82
Conversation
…nheritance so that addition of a new element only requires adding it to the file. The function names are added to a dictionary where the function call is the key, i.e. R(a,b) is represented as 'R'. Downstream code required no modification, as these were added to the globals() dictionary upon import. > The tests were updated so that the inputs and expected outputs are held in dictionaries so that order is no longer important. > The code to extract the elements from the circuit was altered significantly, and a test of this function has been added. It has been demonstrated to support arbitrarily high integers and still properly parses them. The new element, RR, is a resistor whose value is multiplied by 100. I've verified that, when fit, the parameter value is 100-fold smaller than the expeccted R value, and that the fits are identical.
…hat is what was holding up travisCI
I officially have no idea why Travis-CI is failing at the flake8 step after seeming to succeed. Very strange. |
…the error numbers meant before
Pull Request Test Coverage Report for Build 241
💛 - Coveralls |
Awesome! Thanks for such a quick turn around 🚀 I’ll take a dive into this sometime today. The use of a dictionary and globals should make it a lot cleaner and easier to add a new element! Thats awesome. Any technical reason why elements would need to be all caps? From the electrochemistry side I think we need to find a more standard naming scheme, but the way I was thinking about it was as camel case (Wa for Warburg, Wo for Warburg open, etc.). @BGerwe or @lktsui any thoughts/wishes for how we should name the current elements for clarity? |
As far as all-caps is concerned, I just figured that they were all caps now, and that that trend might continue. Enforcing just upper/lower case (mostly no numbers or special characters) wouldn't be much more difficult. |
return eval(buildCircuit(self.circuit, frequencies, | ||
*self.parameters_, | ||
constants=self.constants, eval_string='', | ||
index=0)[0]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of updating the globals() up top, I think we can just pass the circuit elements dictionary (which is a fantastic idea in terms of not importing a bunch of individual elements) directly to the eval function. So it'd just be eval(....., circuit_elements)
. The downside of this is that we either have to add s
, and p
to the circuit elements dict or pass them in as well, but I think it might be better than updating the globals in the whole module in terms of readability/namespace?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ooohh I had forgotten about the ability to pass a dictionary / namespace into eval
, that would make it more readable for sure. The upside of this implementation was that it was less modified code, but the readability has definitely suffered for it. I'll test this out and see how it works.
non_element_functions = ['element_metadata', | ||
'initial_state', | ||
'non_element_functions', | ||
's', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of removing s
and p
from here and treating them as elements? (for easier importing)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a good idea, I've almost got all of the tests passing using that. We just have to make exceptions for them in the "expected outputs given an input" test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be clear - not planning on pushing it right away, so keep picking through the code. I just wanted to make sure there weren't any clear roadblocks
'non_element_functions', | ||
's', | ||
'p', | ||
'K', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
K
is also an element that is used for the LinKK method, so I think it can also be added here too
(0.07107755021941357-0.03427465211788068j), | ||
(0.00199550459845528-0.0019939172581851707j)], | ||
'T': [(1.00041-0.00837309j), | ||
(0.0156037-0.114062j), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added a test for K
, ignoring s
, and p
, and using the num_params attribute of the function wrapper instead of an inputs dictionary
'K': [(1e-1-2e-5j),
(9.6154e-02-1.9231e-02j),
(2.5e-6-5e-4j)],
'RR': [10, 10, 10]}
input_vals = [0.1, 0.2, 0.3, 0.4]
for key, f in circuit_elements.items():
if f.__name__ not in ['s', 'p']:
num_inputs = f.num_params
val = f(input_vals[:num_inputs], freqs)
impedance/models/circuits/fitting.py
Outdated
if element not in allowed_elements or len(element) != 1: | ||
allowed_elements = circuit_elements.keys() | ||
if element not in allowed_elements: | ||
print(element, allowed_elements) | ||
raise ValueError | ||
else: | ||
return eval(element) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have to pass circuit elements to this as well.
Made some quick comments. This is super awesome flexibility. I really like the way Learned something new about globals today, thanks 😃 |
I think that's an awesome idea, I almost have it working locally. Thanks for the K test, I'll import it there and add it to the list! |
…ts dictionary so the globals() namespace stays un-modified. This should help readability. Additionally, s, p, and K are now considered 'elements', and the circuit_elements dictionary is implemented for linKK methods
Looks like you two have already touched on the points I wanted to discuss. I'm really excited about how much easier it will be to add new elements. Some people I wanted to start using impedance.py were hesitant because it didn't have the elements they wanted and adding new ones was such a pain. The Codacy review is failing because of using |
@BGerwe it looks like literal_eval won't work because "The string or node provided may only consist of the following Python literal structures: strings, numbers, tuples, lists, dicts, booleans, and None." I had meant the check_and_eval function to basically be the safety net on eval so we could turn off the codacy check |
That makes a lot of sense. I just wanted to bring attention to the cause of those nasty red X's |
I think the fact that we are now passing a dictionary to I won't be online for a few days, so if you guys want to merge this, feel free! If there are any issues, I'd be happy to help troubleshoot this week! |
Sounds great! |
@all-contributors please add @nealde for code |
I've put up a pull request to add @nealde! 🎉 |
confirmed working multi-letter elements, and cleaned up the element inheritance so that addition of a new element only requires adding it to the file. The function names are added to a dictionary where the function call is the key, i.e. R(a,b) is represented as 'R'. Downstream code required no modification, as these were added to the globals() dictionary upon import.
The tests were updated so that the inputs and expected outputs are held in dictionaries so that order is no longer important.
The code to extract the elements from the circuit was altered significantly, and a test of this function has been added. It has been demonstrated to support arbitrarily high integers and still properly parses them.
The new element, RR, is a resistor whose value is multiplied by 100. I've verified that, when fit, the parameter value is 100-fold smaller than the expected R value, and that the fits are identical. It's just a placeholder, feel free to delete it whenever.
There's also a test that enforces that elements are only allowed to be all-capital letters, so no integers or lower-case letters allowed, or the test will fail.