-
Notifications
You must be signed in to change notification settings - Fork 271
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
Creating derived fields with lambda functions #3434
Comments
Hi, and welcome to yt! Thanks for opening your first issue. We have an issue template that helps us to gather relevant information to help diagnosing and fixing the issue. |
Hi @forrestglines -- can you verify that if the field is defined as a function (potentially in its own closure), it does get added? |
Yes - I tried out a few ways of adding the fields #Add the fields with functions defined in loop - works
for i in range(3,6):
def _field_i(field,data):
return np.full_like(data["density"],i)
ds.add_field(
name=("gas", f"field_{i}"),
function=_field_i,
sampling_type="local",
units="g/cm**3"
)
#Add fields
def _field_6(field,data):
return np.full_like(data["density"],6)
ds.add_field(
name=("gas", "field_6"),
function=_field_6,
sampling_type="local",
units="g/cm**3"
)
for i in range(7):
name = ("gas",f"field_{i}")
print(f"{name} in ds.field_info:", name in ds.field_info)
if name in ds.field_info:
print(f" {name} mean = {ds.all_data()[name].mean()}")
These all work. However, defining the functions within the for-loop works as expected in this example but in my analysis code leads to them all sharing the last added function (i.e. they would all print |
Looks like a bug to me. I'm not 100% sure it that it should work with lambdas (or generally with non-function callables), though I would be inclined to think so. On the off chances that there's a good, deep reason not to add support for it, it should at the very least produce a clear error message. |
My guess is that there's something yt does with the function handles that is not available to lambdas. To make the functions work the way you're wanting to (which I recognize is a stopgap) you can try adding a layer of enclosure to them. For instance,
That should do it. |
yes this is how it is done internally. |
This works -- both in my example and in my analysis code. I'm still a little confused and curious as to what features of lambdas are missing which make them break as a derived field. |
After a bit of googling, I found another piece of the puzzle. The function only needs to be given a name other than for i in range(3):
name = ("gas", f"field_{i}")
_my_field = lambda field,data : np.full_like(data["density"],i)
_my_field.__name__ = "lambda"
ds.add_field(
name=name,
function=_my_field,
sampling_type="local",
units="g/cm**3"
) works fine. The only check I can find for |
Fascinating ! @matthewturk, it seems you authored this line 8yrs ago but the commit message doesn't help much, any idea if this check could have become irrelevant ? |
Bug report
Bug summary
Adding fields using a lambda function fails to add the field to a dataset. Trying to access created fields that use a lambda function results in a
YTFieldNotFound
exception.Code for reproduction
Actual outcome
None of the fields defined with lambda functions get added to
field_info
. No errors or exceptions are reported byadd_field
. But when I try to access the supposedly created fields, I get aYTFieldNotFound
exception.Expected outcome
Lambda functions should work with
add_field
like other function objects. Or it should be documented that they don't work.I remember running into this issue once before several years ago when I was just starting out with
yt
, it might have existed for a while.Version Information
4.0.dev0
, installed from sourceThe text was updated successfully, but these errors were encountered: