Skip to content
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

Creator on the node object #58

Open
samwaseda opened this issue Oct 31, 2023 · 2 comments
Open

Creator on the node object #58

samwaseda opened this issue Oct 31, 2023 · 2 comments
Labels
enhancement New feature or request

Comments

@samwaseda
Copy link
Member

I took the following lines from @JNmpi ’s example:

structure = wf.create.atomistics.Bulk('Al', cubic=True)
repeat = wf.create.lammps.Repeat(structure = structure, repeat_scalar=3)

In current pyiron_atomistics, repeat is attached to structure, which has a huge advantage that you have only the related items appear in the auto-complete list. I don’t know how difficult it would be, but I would like to follow the same spirit and have create on the node level, so that we can set structure.create.lammps.Repeat, where on the lammps level there are only items shown which can have structure as an argument. I don’t mind having to write structure explicitly in the argument. The object type should be parsed from the function, i.e. from def BulkNode(blablabla) -> pyiron_atomistics.atomistics.structure. If the type is not given, it shows simply all possible entries.

@samwaseda samwaseda added the enhancement New feature or request label Oct 31, 2023
@JNmpi
Copy link

JNmpi commented Oct 31, 2023

I very much like the idea. It should be rather easy to realize this concept once we have ontologic typing included. A quick fix that would work with the present implementation would be to create node libraries that contain only specific nodes. For example, we could have a library atomistics.structure_to_structure were only nodes that take an input structure as an argument and which return a structure for further processing. Nodes that could be included in such a library would be repeat, apply_strain, substitute etc. Having such well-structured node libraries would make it highly intuitive to find the relevant nodes.

@liamhuber
Copy link
Member

liamhuber commented Oct 31, 2023

Direct response

Yeah, I like this idea! It is certainly possible, because we have exactly this over on ironflow with the node-suggestion menu. In fact, making something like this available early in the codebase would make it trivially easy to implement suggestion menus like ironflow has in a gui.

@JNmpi, I fully agree it's much easier once we have ontological typing. I think we can have a weaker version already with the plain typing. The suggestions would sometimes be too broad with classical typing, i.e. you may require a surface structure and have a bulk structure creator recommended to you, but we can still do it.

I would amend the original suggestion to say rather that channels should have a creator (or creator-like) object attached to them. I think showing all possible partners for an entire node is simply too broad. Of course, in the case of SingleValueNode we could have a creator on the node corresponding to the single output channel.

I would also suggest that if the type is not given, zero suggestions are shown rather than all of them.

Finally, I also see room to extend this from creation to connection in the form of wf.some_node.outputs.some_channel.connect.to.[tab completion menu] where the menu is populated by sibling node instances who have commensurate channels.

Pseudocode thoughts

In this paradigm I would imagine all the following examples are identical:

from pyiron_workflow import Workflow
wf = Worfklow("create_from_channels")
# ... register whatever packages we need

wf.structure = wf.create.atomistics.Bulk("Al")
wf.calc = wf.create.atomistic_codes.Lammps(structure=wf.structure)
...

wf.structure = wf.create.atomistics.Bulk("Al")
wf.structure.outputs.structure.create.Lammps(label="calc")
# It gets added to the same wf because wf.structure knows its parent
# The data connection gets set up on creation because we know what
# input our output is seeing that it agrees with
# (there is an edge case here for nodes that have two channels
# with the same type hint we'd need to resolve...)
...
wf.structure = wf.create.atomistics.Bulk("Al")
wf.structure.create.Lammps(label="calc")
# Bulk is a single value node, so we can unambiguously do it from the node
...

wf.calc = wf.create.atomistic_codes.Lammps()
wf.calc.inputs.structure.create.Bulk(label="structure")
# We can do it from the other side just as easily

Implementation thoughts

As for implementation....that might be trickier. Not impossible, I don't think, just more work (EDIT: Ok, maybe impossible for macros without some serious changes in infrastructure and user behaviour). The main issue I see is that the IO channels don't actually exist until after instantiation -- so searching them at the class-level to instantiate compatible classes is tricky. You can't trivially instantiate channels on the classes themselves, or updates to the channels get propagate to all instances of that channel.

ryven got around this by having "port [channel] blueprints", which transformed into actual channels at instantiation time. I had to do some work to extend these with typing information. This approach works, but I found it a little ugly and so I did things without this intermediate class here.

Since #53, we do store type hints at the class level, so one way around the meta-channel may be to simple directly parse those hints. (This works at the regular typing level -- for ontological typing we'd need to wait and see how we implement those hints.)

Of course, those type hints are only available for function nodes. Macros are a whole different deal: we allow the inputs_map and outputs_map to be specified in the function that builds the macro, and these maps can change what IO is available on the macro, and we don't run this creator function until instantiation. So accessing the type hints before instantiation for macros poses a serious challenge.

The way to get make these things easier is to have classes explicitly define their IO at the class level, but doing this automatically (especially for macros) without ever having users even know what a class is becomes...difficult. Of course you can always make new functional nodes by subclassing Function, so perhaps we can do a thing where power-users who are aware of classes can leverage this knowledge to create IO-hint-aware macros, but anyone who just decorates a macro building function gets excluded from the suggestion list. That's not a super friendly solution, IMO.

In the short and medium term, Joerg's suggestion to logically group node is a good step to improve usability that doesn't require so much fancy infrastructure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants