Fix indexed array assignment + indexed derived types and a bit more - #184
Fix indexed array assignment + indexed derived types and a bit more#184ken-lauer wants to merge 19 commits into
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #184 +/- ##
==========================================
+ Coverage 97.22% 97.29% +0.06%
==========================================
Files 9 9
Lines 2166 2365 +199
Branches 361 416 +55
==========================================
+ Hits 2106 2301 +195
- Misses 35 39 +4
Partials 25 25
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
Thank you so much, this is an epic contribution. Derived type array assignment has been ignored for a very long time because the original code was never designed to handle it, and it happened to be rare enough that there wasn't much demand. It will take me some time to process all of it, but overall it looks good to me. As for acknowledging Claude, this advice seems like the best to me: https://docs.kernel.org/process/coding-assistants.html Something in the commit log like this should be more than enough. If you tell me the LLM that was used, I can squash the commits and append it to the end. (Or, if you wanted to rebase the commits with documented commit messages, that would also be great, but not necessary.) |
Assisted-by: Claude:claude-3-opus
Assisted-by: Claude:claude-3-opus
We can't know the fields of the struct, unfortunately. If the user mixes these forms for the same index, we can't effectively merge those. Still better than before. Assisted-by: Claude:claude-3-opus
Assisted-by: Claude:claude-3-opus
Assisted-by: Claude:claude-3-opus
Assisted-by: Claude:claude-3-opus
01fef02 to
b1e51ad
Compare
I'm glad you think so - and I hope this is a good basis for full support. It's pretty close, I think.
I completely understand. I would typically complain if someone gave me such a large PR to review, and here I am proposing this as a first time contributor...
I rebased and marked the commits that were largely LLM-assisted as you requested. If this ends up getting squashed into one commit with that attribution, that's OK with me - it's your call as to if/when/how to take this in. |
|
A polite nudge to see where you're at on this, @marshallward. Don't worry about it if you don't have the time, but I was curious if perhaps you'd changed your mind after seeing the PR diff (and maybe recoiling in horror 😄 ) |
|
Thanks for the nudge, I looked it over and have started documenting the overall problem. I think I understand the approach but have been looking to see if it can be done with fewer (if any) metafields like I was planning to ping you because I tried this PR for the most recent issue #185, which I thought this would address, but didn't seem to work for me. Do you see the same? |
|
Hmm, reflecting on that issue and looking back over the changes after a couple months myself, it looks like I had some bad test cases that misrepresented how the scattered struct array/value data should look. Some of them definitely need fixing, and this PR definitely should not be merged as-is. I'll move it back to draft. I'll poke around with this branch a bit more. I might also propose a different approach with a bit less bookkeeping metadata/metafields. Though it complicates things a bit, personally, I'd still like to see the namelists round-tripped to the same form (e.g., I'm betting you can come up with something cleaner eventually. That said, if what I propose ever gets to a point where you want to use it - great! |
Assisted-by: Claude:claude-3-opus
|
I'll post where my thinking is up to on this. It duplicates some of what you and others have written but it will help me step through it. The original sin is based on simple namelists like the following. They have always been naively interpreted as arrays, but there are in fact two possiblities.
This first report of this problem appeared in #110 but it was incorrectly identified as an edge use case. Several issues later have shown otherwise. In practice, the above example is not an issue. It is stored as Arrays of derived types as in #110 introduce new difficulties. There are again two interpretations:
But we could just as easily interpret If you work up to higher dimensions, you see similar issues. For example: Is The one thing we can say for certain is that it is not
The biggest question to me at the moment is how to capture this ambiguous state, rather than just defaulting to one or the other. Unfortunately I don't have time to follow up at the moment, but the general point is that it would probably be better to rethink of the content as lists-of-data that are held on various containers. (I will try to follow up later tonight.) |
|
This is great to see. I am really in need of this for my nml-tools package. Do you need any help here? |
|
I think we're all generally on the same page. Thanks for the great summary of the overall issue, @marshallward. My original intent to get around that ambiguous scalar array vs anonymous derived type field issue was to keep track well enough to round-trip the data into the same representation. I don't think what this PR does is perfect in that regard, though. Things likely could be much simpler. @MuellerSeb, I'm glad to hear there's more demand for this functionality. It's definitely something my team will be happy to have, once it makes its way into f90nml. As for help (at least on my end, @marshallward may have other ideas) if you could run this branch against your own test cases and such that would be useful. It may lead to either fixing this up or an entirely new approach. |
|
For nml-tools I now implemented a schema aware parser built into nml-tools. This is much easier than guessing the underlying variable types from the present namelist itself like f90nml does (with good success BTW). But that is only usable to validate a namelist against a given schema and doesn't convert a namelist to a dictionary (yet). |
Context
Closes #110
Closes #127
And maybe others?
f90nml was failing miserably for namelists from this charged particle physics simulation library Bmad, and this PR is the result of my poking around into trying to address that. (See all of the
tao.initfiles in that repository, they are all Fortran namelists, many of which fail to parse with the current master)So this ended up being a big set of changes and fixes. I started out with attempting this entirely manually, but admittedly did get Claude's help here. If that's against your contribution rules, I completely understand! Perhaps it at least can be a basis for a better fix.
If that's still OK, then I expect you might want me to try breaking up this PR into several. I can make an attempt, if there's a greater chance for these changes to get merged.
Changes / fixes
Parent-indexed derived-type slice assignment:
arr(1:N)%foo = v1, ..., vNnow parses intoarr.foo = [...]and round-trips back to the slice form.Open-ended parent-indexed bound:
var(1:)%ele_name = ... (and var(:N)%...)gets the bound inferred from the value count instead of crashing/dropping data.
Single-value open-ended slice:
var(1:)%ele_name = 'x'correctly produces a one-element listSliced field plus per-element field on the same array:
Positional derived-type rows, which can have mixed types:
Positional then field on the same index - this is stored as
_positional_row:Unindexed positional then field:
Data getting scattered into different, previously-parsed derived type lists:
For example, after
var(1)%ele_name, var(2)%ele_name, var(3)%ele_nameare set, a follow-upvar(1:3)%attribute = 'k1', 'k2', 'k3'distributes valuesinto the existing elements rather than overwriting them.
Nested parent-indexed derived types, along with deeper nesting (hopefully):
Strided parent index:
Parses into
[10, None, 30, None, 50]and round-trips back to the strided form with a bit of stride detection logic.Multi-value indexed assignment:
This is treated as a positional row
Ninstead of a flat one-dimensional vector starting at N.FIndexdebug repr: added__str__so I could see what was going on with it.There's additional metadata for keeping track of what's positional, when slicing was used, when parent-based indexing was used. The
"_positional_row"value is special in the value dictionary, as when you combine positional derived type setting and fieldname-based settings they can clash (... why do people do this and why does Fortran allow it? Ugh.).The additional metadata helps with round-tripping back to namelist files especially.
I admittedly did not get to testing patching with these, but it's past 5PM on a Friday. So I think that's good enough for now.