Comments (23)
I think giving the option in UI is a good idea.
You can use an enum to display the properties like so:
bpy.types.Scene.MN_center_type = bpy.props.EnumProperty(
name="Method",
items=(
('mass', "Mass", "Adjust the centre of mass to be at the world origin.", 0),
('centroid', "Centroid", "Adjust the centroid (ignoring mass) to be att he world origin.", 1)
)
)
Then display that property on each of the panels for the import methods.
The panels are defined under io/wwpdb
, io/local
io/md
for the relevant import methods.
from molecularnodes.
Yep please make a PR! Can have a look at it then :)
from molecularnodes.
I'm happy to include the masses in the data.py
dictionaries - and would be something useful to have in MN going forward.
When importing via downloading from the PDB or parsing a local file, biotite
is used and MDAnalysis
is only used when importing via the MD
import method. Trying to use methods from MDAnalysis
while importing via biotite
would get messy and I'd ideally want to avoid it.
If we get the masses from the data.py
though, the com
calculation could happen during import, or it could also be done via nodes (probably options for both).
If first you wanted to create a PR to include the masses that would be great. I can give some help with turning that into an attribute if you'd like. If you'd like to contribute a com
calculation we can use that, otherwise that can be implemented later.
from molecularnodes.
Looking at that dictionary you linked as well - I have also been meaning to create a dictionary for converting from atomic_number
to letters etc for potentially writing .pdb/.cif
files. We could replace my existing dictionary with the ones you have there.
from molecularnodes.
Before I make a PR, can you explain where the elements dictionary is used? I'm noticing instances of duplicate entries (ex: Na and NA both mapping to sodium), which suggest maybe the dictionary is used for interpreting atom names used in structure files. Similarly, there are some interesting entries such as D mapping to a carbon atom instead of deuterium. And a smattering of course-grained particle types also included in the dictionary.
Maybe a second dictionary is appropriate that contains a mapping between standard atom names used in structure files (originating from AMBER, CHARMM, OPLS force fields or crystallographic naming conventions that I'm not familiar with) and their associated element. This way, hopefully the ambiguity/diversity of atom name formatting gets accurately mapped to the element symbol and subsequently can be mapped to the element's atomic number/vdw radius/full name/ mass (info held within the elements
dictionary).
Additionally, there are a whole bunch of 100 values in the 'vdw_radii'
keys in the elements
subdictionaries, which I suspect are just place-holders. Should a default vdw_radii value be set, for visualization purposes, that is overwritten if an atom has an element with a 'vdw_radii'
key in its elements
dictionary entry?
from molecularnodes.
Before I make a PR, can you explain where the elements dictionary is used?
They are used when creating the models inside of Blender, usually to translate from string to integer values, or for looking up values like VDW radii.
When parsing regular structure files:
MolecularNodes/molecularnodes/io/parse/molecule.py
Lines 384 to 389 in f3dbff0
MolecularNodes/molecularnodes/io/parse/molecule.py
Lines 438 to 445 in f3dbff0
When importing a MD trajectory:
MolecularNodes/molecularnodes/io/parse/mda.py
Lines 172 to 176 in f3dbff0
MolecularNodes/molecularnodes/io/parse/mda.py
Lines 180 to 185 in f3dbff0
I'm noticing instances of duplicate entries (ex: Na and NA both mapping to sodium), which suggest maybe the dictionary is used for interpreting atom names used in structure files. Similarly, there are some interesting entries such as D mapping to a carbon atom instead of deuterium. And a smattering of course-grained particle types also included in the dictionary.
Maybe a second dictionary is appropriate that contains a mapping between standard atom names used in structure files (originating from AMBER, CHARMM, OPLS force fields or crystallographic naming conventions that I'm not familiar with) and their associated element. This way, hopefully the ambiguity/diversity of atom name formatting gets accurately mapped to the element symbol and subsequently can be mapped to the element's atomic number/vdw radius/full name/ mass (info held within theelements
dictionary).
There are some entries relating to course grained simulations and other non-standard elements etc. I would be in favor of us moving those out into a separate backup dictionary perhaps that can be used as a fallback, to help with organisation.
Additionally, there are a whole bunch of 100 values in the
'vdw_radii'
keys in theelements
subdictionaries, which I suspect are just place-holders. Should a default vdw_radii value be set, for visualization purposes, that is overwritten if an atom has an element with a'vdw_radii'
key in itselements
dictionary entry?
You are correct that these are currently just placeholders. I just at the time (when I very first started writing this add-on years ago) wither couldn't be bothered or couldn't reliably get values for those elements and so left them as is. Would be in favor of removing them and using just a fallback value.
I have been thinking also of potentially removing the vdw_radii
attribute from being added explicitly from being added, and instead turning this dictionary into a lookup table inside of Geometry Nodes that is only used when needed (for spheres, bond calculations etc). I wouldn't be doing that till Blender 4.1 though when they introduce some new nodes for it.
from molecularnodes.
Happy to discuss more about potential design implementations as well.
I'm still not super happy with how I internally go about getting the attributes added to the structure. It was a solution that worked at the time and I just haven't revisited it since.
from molecularnodes.
Great!
-
I'm gonna remove the placeholder vdw_radii values, remove duplicate and non-element entries (stashing them in a backup dict), and add atomic masses to the
elements
dict. -
For vdw_radii, a default value of 100 picometers can be used in line 185 of
MolecularNodes/molecularnodes/io/parse/mda.py
Lines 180 to 185 in f3dbff0
MolecularNodes/molecularnodes/io/parse/molecule.py
Lines 438 to 445 in f3dbff0
-
I'll implement a function in both molecule.py and mda.py to gather the atomic masses into a numpy array, mirroring the functions used for
vdw_radii
.
Towards this last task and
I'm still not super happy with how I internally go about getting the attributes added to the structure. It was a solution that worked at the time and I just haven't revisited it since.
What's wrong with using bpy.data.objects[MN_object_name].data.attributes[attribute_name]
and then converting it to a numpy array or mathutils matrix?
Finally, are there unit/integration tests for data.elements
or instances where changes to data.elements
will cause tests to fail? I haven't done too much digging into the MolecularNodes/tests
directory.
from molecularnodes.
Finally, are there unit/integration tests for data.elements or instances where changes to data.elements will cause tests to fail? I haven't done too much digging into the MolecularNodes/tests directory.
I haven't got any tests specfically for the data.py
files, but they are used for most of the other tests. If you'd like to add some tests specifically for them, I won't say no to more robust tests.
What's wrong with using bpy.data.objects[MN_object_name].data.attributes[attribute_name] and then converting it to a numpy array or mathutils matrix?
I am unsure what you are saying here. I have happy with the mn.blender.obj.set_attribute()
and mn.blender.obj.get_attribuet()
which get and set attributes from meshes, these take and return numpy arrays.
What I mean more specifically is that I set up all the potential attributes as a function (for the example of the vdw_radii, att_vdw_radii()
, which is only evaluated when the function is called. This way I can delay the creation of attribute into a simple loop with try
except
in case the attribute can't be generated. I am unsure what would be a better approach, of there even would be a better approach, but it feels a bit messy for my liking.
from molecularnodes.
Yeah, thinking about this more, the data.elements
dictionary is used whenever a structure is loaded - so basically every test is potentially affected by the changes in that dictionary, albeit not likely resulting in any fatal errors. The most precarious type of changes being made...
I don't think a test handle needs to be written around the data.py
data structures directly. I guess a better question for me to ask is, how do I run all or a subset of the tests before doing the PR? My previous experience has been using a series of test handles stashed in module files in if __name__ == '__main__':
blocks. Then, just run python module.py
in a terminal and check the output via assert statements. Is it a similar process here, just in the blender python interpreter? Maybe I'm being overly cautious here though.
from molecularnodes.
The tests I run outside of Blender, utlising the bpy
module that is installable from pip. You can run the test suite inside of Blender but it can be a bit of a mess around.
Running these inside of the MolecularNodes
folder.
conda create -n molecularnodes python==3.10
conda activate molecularnodes
pip install -e .
pip install pytest pytest-snapshot pytest-cov scipy
To run run tests:
# run all tests with verbose output
pytest -v
# run pattern matched tests for a string
pytest -v -k attribute
# run tests in a single file
pytest -v tests/test_attribute.py
from molecularnodes.
Apologies as I do need formalise all of this better in a CONTRIBUTING.md
from molecularnodes.
I've got code for calculating the Center of Mass but I'm not sure where to place it in the module files. Should users be given the choice to center by the CoG or CoM in the Scene -> Molecular Nodes -> import options?
Here's the code block though:
def center_by_CoM( positions, masses):
"""
:parameter positions: np.ndarray, shape = (nAtoms, 3), cartesian coordinates of the structure(s), assumed units of \AA
:parameter masses: np.ndarray, shape = (nAtoms,), atomic masses of atoms in the structure(s), assumed units of daltons
and assumed same order as positions
:return centered_positions: np.ndarray, shape = (nAtoms,3), CoM translation removed from the coordinates
"""
return positions - np.sum(masses[:,None] * positions, axis = 0) / np.sum(masses)
from molecularnodes.
bpy.types.Scene.MN_center_type = bpy.props.EnumProperty( name="Method", items=( ('mass', "Mass", "Adjust the centre of mass to be at the world origin.", 0), ('centroid', "Centroid", "Adjust the centroid (ignoring mass) to be att he world origin.", 1) ) )Then display that property on each of the panels for the import methods.
I don't have a great sense for what this will look like in the UI. Is it going to be a single check box for the centre
option that then unlocks a choice for mass
or centroid
via a drop-down menu or further checkboxes?
from molecularnodes.
MN_import_centre is defined in ~/molecularnodes/props.py. I assume that's where the MN_center_type, suggested above, would be defined.
Then, in wwpdb.py and local.py, a few chunks of codes need to be updated.
- The
def panel(layout, scene):
functions need to havegrid.prop(scene, 'MN_center_type')
added. - Add a
centre_type
keyword argument to thefetch()
function (MolecularNodes/molecularnodes/io/wwpdb.py
Lines 7 to 40 in f3dbff0
MolecularNodes/molecularnodes/io/wwpdb.py
Lines 94 to 102 in f3dbff0
- Do similar for the
load()
function inMolecularNodes/molecularnodes/io/local.py
Lines 22 to 55 in f3dbff0
MolecularNodes/molecularnodes/io/local.py
Lines 78 to 86 in f3dbff0
Then I'll need to update the Molecule
class' create_model()
method (
MolecularNodes/molecularnodes/io/parse/molecule.py
Lines 176 to 262 in f3dbff0
_create_model
function (MolecularNodes/molecularnodes/io/parse/molecule.py
Lines 321 to 606 in f3dbff0
centre_type
keyword argument to both.
In the _create_model()
function, the
MolecularNodes/molecularnodes/io/parse/molecule.py
Lines 344 to 350 in f3dbff0
if centre and centre_type == 'centroid'
. If true, run through the code as normal, removing the centroid from the locations
. Otherwise, if centre and centre_type == 'mass'
, need to wait to center the structure until after all attributes are looped over and added to the blender object (line 568). Once atom attributes have been created for the MN object's atoms, then the elements
dictionary can be used to map that atomic_number array to an atomic_mass array, which can then be thrown into the code above to calculate the CoM. Remove the CoM from locations and update the position
attribute.from molecularnodes.
Log file from the pytest -v
is at https://github.com/rbdavid/MolecularNodes/blob/main/tests_results.txt. I haven't done any digging about the various failures. There wouldn't be a log of test results from the original 4.0.11 release, would there?
from molecularnodes.
All of the logic looks good that you were laying out above. Instead of adding another attribute, we could change centre
to take an enum, with default to None
meaning no centering. I think that would be better.
from molecularnodes.
For the test result failures - for now run pytest --snapshot-update
and it will update the failing snapshots with their new values. Where there are snapshots that say The selected attribute 'entity_id' does not exist on the mesh. Possible attributes are: attribute_names=['b_factor',...
It makes sense that they would fail and change - but I should update them in the future that they wouldn't change with the addition of another attribute. Might be something that I tweak in another PR and then you work from that if you'd prefer (and would result in a smaller diff for your PR).
from molecularnodes.
Yeah, I'd rather not be the one who pushes the pytest --snapshot-update
since I haven't done any work on verifying previous and current tests.
from molecularnodes.
bpy.types.Scene.MN_center_type = bpy.props.EnumProperty( name="Method", items=( ('mass', "Mass", "Adjust the centre of mass to be at the world origin.", 0), ('centroid', "Centroid", "Adjust the centroid (ignoring mass) to be att he world origin.", 1) ) )
So, if I want to add the default value of None
to this enum, just do default=None,
within that chunk of code? Or do I also need to add a third item to the items tuple?
Something like
('', 'None', 'Do not centre the structure on the world origin.', _some_value_)
where maybe the _some_value_
should be zero and the other two items should be shifted by 1? I have zero experience making a GUI panel for Blender.
from molecularnodes.
I just merged #447 which should remove most of the failed snapshot tests. Those that now fail should be legitimate failures.
from molecularnodes.
So, if I want to add the default value of None to this enum, just do default=None, within that chunk of code? Or do I also need to add a third item to the items tuple?
The enum property types can only take strings, so yes you could supply ''
as an option - but it might be better from a UX to keep the tickbox for centering. If unticked then the type is grayed out, if ticked then the user can specify the type of centering.
It would look like the current option for adding a style, which can be disabled, but when enabled provides a dropdown menu (which is how the enum is displayed) to choose the type of style.
MolecularNodes/molecularnodes/io/wwpdb.py
Lines 132 to 135 in 5ac81da
from molecularnodes.
Yeah, that's perfect! I'll get that implemented. Other than that and tests, I'm not sure if much more is needed. Should I make a PR or wait for word from you?
from molecularnodes.
Related Issues (20)
- String selections for non-MD molecules
- AttributeError: 'ShaderNodeBsdfPrincipled' object has no attribute 'node_tree' HOT 1
- Select Sphere incorrect
- `By CA` should fallback on atoms if no CA
- Store In Memory option for trajectories missing HOT 6
- 6VBU Doesn't import as BCIF
- Add-on needs to respect online access permissions
- Something is different in installation page HOT 2
- Missing nucleic side chains displays incorrectly for ribbon / cartoon
- Formatting issues of the PDB file HOT 1
- Relative path fails for opening local file HOT 2
- Starfile arrows aren't colored
- Disable MNSession warning
- Change of License
- Can't interpolate .xtc trajectory with animation node. (No frames collection) HOT 2
- Trouble loading trajectory HOT 3
- Centre on Selection `offset` is broken HOT 1
- Build extension via GHA
- Move all custom attributes to Molecule / Trajectory
- VSCode development addon isue with extension? HOT 2
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 molecularnodes.