Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into bcif
Browse files Browse the repository at this point in the history
  • Loading branch information
corredD committed Sep 25, 2024
2 parents fb49c99 + 475b278 commit 8fbc753
Show file tree
Hide file tree
Showing 24 changed files with 2,292 additions and 994 deletions.
2 changes: 1 addition & 1 deletion docs/example_animations.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ To morph between 3 conformations of ATP synthase use ChimeraX commands "open 6n2
::: callout-caution
# Requires MDAnalysis Installed

To follow this particular tutorial, ensure you have first [installed Molecular Nodes properly](installation.md), including the optional MDAnalysis python package.
To follow this particular tutorial, ensure you have first [installed Molecular Nodes properly](installation.qmd), including the optional MDAnalysis python package.
:::

Download the trajectory files from the the [CHARMM-GUI website](https://charmm-gui.org/?doc=archive&lib=covid19):
Expand Down
14 changes: 7 additions & 7 deletions docs/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@
if submenu.description:
file.write(submenu.description)
file.write("\n\n")
for item in submenu.items:
if item.is_break:
for menu_item in submenu.items:
if menu_item.is_break:
continue
if item.backup is not None:
name = item.backup
if menu_item.backup is not None:
name = menu_item.backup
else:
name = item.name
doc = noodlenotes.MenuItemDocumenter(item)
name = menu_item.name
documenter = noodlenotes.MenuItemDocummenter(menu_item)

file.write(doc.as_markdown())
file.write(documenter.as_markdown())
file.write("\n\n")
3 changes: 2 additions & 1 deletion docs/nodes/index.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ At any point you can view the internals of the node groups that are included wit
With a node selected, you can <kbd>Tab</kbd> to enter a selected node, and use <kbd>Ctrl</kbd> + <kbd>Tab</kbd> to exit the node group.
You can also do the same by right clicking.
Feel free to tweak the internals of node groups, but beware that changing one node group will change that node group for all othe uses of it.
Starting a new Blender session will ensure that the node groups are fresh and 'factor reset'.
Starting a new Blender session will ensure that the node groups are fresh and 'factor reset'.

2 changes: 1 addition & 1 deletion docs/noodlenotes/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .documenter import TreeDocumenter, MenuItemDocumenter
from .documenter import MenuItemDocummenter, Documenter
65 changes: 42 additions & 23 deletions docs/noodlenotes/documenter.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import bpy
import pathlib
import sys

from .interface import InterfaceGroup, InterfaceItem
from . import markdown
from typing import List

TOP_FOLDER = pathlib.Path(__file__).resolve().parent.parent.parent
sys.path.insert(0, str(TOP_FOLDER))

class TreeDocumenter:
def __init__(
self, tree: bpy.types.NodeTree, description: str = None, image: str = None
) -> None:
from molecularnodes.ui.menu import Menu, MenuItem, CustomItem, Item, Break


class Documenter:
def __init__(self, tree: bpy.types.NodeTree, menu_item: MenuItem = None) -> None:
self.tree = tree
self.items = [InterfaceItem(x) for x in tree.interface.items_tree]
self.inputs = InterfaceGroup([x for x in self.items if x.is_input])
self.outputs = InterfaceGroup([x for x in self.items if x.is_output])
self._description = description
self.image = markdown.Video(image)
self.menu_item = menu_item
self.level = 2

@property
Expand All @@ -24,20 +29,37 @@ def title(self) -> str:
return f"## {self.tree.name.removesuffix('_')}"

def description(self) -> str:
if self._description:
return self._description + "\n\n" + self.tree.description
return self.menu_item.description + "\n\n" + self.tree.description

def videos(self) -> List[str]:
links = self.menu_item.videos

if links is None:
return None

for x in links:
if x is None:
return None

if isinstance(links, str):
links = [links]

if not all([isinstance(x, str) for x in links]):
raise ValueError(f"All url values must be strings: {links=}")

videos = "\n\n".join(
[markdown.Video(x).as_markdown() for x in links if x is not None]
)

return self.tree.description
return "\n\n" + videos + "\n\n"

def collect_items(self):
items = [
self.title(),
self.description(),
self.image.as_markdown(),
"### Inputs",
self.inputs.as_markdown(),
"### Outputs",
self.outputs.as_markdown(),
self.videos(),
self.inputs.as_markdown("Inputs"),
self.outputs.as_markdown("Outputs"),
]
return [item for item in items if item is not None]

Expand All @@ -47,14 +69,11 @@ def as_markdown(self) -> str:
return text


def MenuItemDocumenter(menu_item) -> TreeDocumenter:
if menu_item.backup:
tree = bpy.data.node_groups[menu_item.backup]
else:
tree = bpy.data.node_groups[menu_item.name]
class MenuItemDocummenter(Documenter):
def __init__(self, menu_item: MenuItem) -> None:
super().__init__(tree=menu_item.tree, menu_item=menu_item)

doc = TreeDocumenter(
tree=tree, description=menu_item.description, image=menu_item.video_url
)

return doc
class TreeDocumenter(Documenter):
def __init__(self, tree: bpy.types.NodeTree) -> None:
super().__init__(tree=tree)
40 changes: 27 additions & 13 deletions docs/noodlenotes/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ def type(self) -> str:
return "PANEL"
return "`{}`".format(self.item.socket_type.replace("NodeSocket", ""))

@property
def is_vector(self) -> bool:
return self.type in ["Vector", "Color", "Rotation", "Matrix"]

def __len__(self) -> int:
if self.type == "PANEL":
return 0
elif self.type in ["Vector", "Rotation"]:
return 3
elif self.type in ["Color"]:
return 4
elif self.type == "Matrix":
return 16
else:
return 1

@property
def default(self, round_length: int = 3) -> str:
try:
Expand Down Expand Up @@ -89,19 +105,9 @@ def description(self):
return ""

def max_length(self):
info_to_test = [self.description, self.min, self.max, self.default]
info_to_test = [self.description, self.min, self.max, self.default, self.type]
return max([len(x) for x in info_to_test if x is not None])

def formatted(self):
text = f"Default Value: {self.default}\n"
try:
text += f"Min: {self.min}\n"
text += f"Max: {self.max}\n"
except AttributeError:
pass

return text


class InterfaceGroup:
def __init__(self, items: List[InterfaceItem]) -> None:
Expand Down Expand Up @@ -144,8 +150,16 @@ def body(self) -> str:
def tail(self) -> str:
return '\n\n: {tbl-colwidths="[15, 10, 55, 20]"}\n\n'

def as_markdown(self):
return self.top_line() + self.sep() + self.body() + self.tail() + "\n"
def as_markdown(self, title: str = "", level: int = 3):
body = self.body()
if not body:
return ""
hashes = "#" * level
lines = f"{hashes} {title}\n\n"
for x in [self.top_line(), self.sep(), self.body(), self.tail(), "\n"]:
lines += x

return lines

def __repr__(self) -> str:
return self.as_markdown()
2 changes: 1 addition & 1 deletion docs/noodlenotes/markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ def __init__(self, url: str, caption: str = "") -> None:

def as_markdown(self) -> str:
if not self.url or self.url == "":
return None
return "![]()"
return f"![{self.caption}]({self.format_url()})"

def format_url(self) -> str:
Expand Down
4 changes: 2 additions & 2 deletions molecularnodes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ def register():
for op in all_classes:
try:
bpy.utils.register_class(op)
except Exception:
# print(e)
except Exception as e:
print(e)
pass

bpy.types.NODE_MT_add.append(MN_add_node_menu)
Expand Down
Binary file modified molecularnodes/assets/MN_data_file_4.2.blend
Binary file not shown.
7 changes: 7 additions & 0 deletions molecularnodes/blender/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,10 @@ def path_resolve(path: Union[str, Path]) -> Path:
return Path(bpy.path.abspath(str(path)))
else:
raise ValueError(f"Unable to resolve path: {path}")


def active_object(context: bpy.types.Context = None) -> bpy.types.Object:
if context is None:
return bpy.context.active_object

return context.active_object
11 changes: 5 additions & 6 deletions molecularnodes/blender_manifest.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
schema_version = "1.0.0"

id = "molecularnodes"
version = "4.2.6"
version = "4.2.7"
name = "Molecular Nodes"
tagline = "A toolbox for molecular import and animation in Blender"
maintainer = "Brady Johnston<[email protected]>"
Expand Down Expand Up @@ -35,7 +35,6 @@ wheels = [
"./wheels/biotite-0.41.2-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/biotite-0.41.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/biotite-0.41.2-cp311-cp311-win_amd64.whl",
"./wheels/colorama-0.4.6-py2.py3-none-any.whl",
"./wheels/contourpy-1.3.0-cp311-cp311-macosx_10_9_x86_64.whl",
"./wheels/contourpy-1.3.0-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/contourpy-1.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
Expand Down Expand Up @@ -64,10 +63,10 @@ wheels = [
"./wheels/msgpack-1.1.0-cp311-cp311-win_amd64.whl",
"./wheels/networkx-3.3-py3-none-any.whl",
"./wheels/packaging-24.1-py3-none-any.whl",
"./wheels/pandas-2.2.2-cp311-cp311-macosx_10_9_x86_64.whl",
"./wheels/pandas-2.2.2-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/pandas-2.2.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/pandas-2.2.2-cp311-cp311-win_amd64.whl",
"./wheels/pandas-2.2.3-cp311-cp311-macosx_10_9_x86_64.whl",
"./wheels/pandas-2.2.3-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/pandas-2.2.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
"./wheels/pandas-2.2.3-cp311-cp311-win_amd64.whl",
"./wheels/pillow-10.4.0-cp311-cp311-macosx_10_10_x86_64.whl",
"./wheels/pillow-10.4.0-cp311-cp311-macosx_11_0_arm64.whl",
"./wheels/pillow-10.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
Expand Down
3 changes: 1 addition & 2 deletions molecularnodes/entities/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from .molecule.pdb import PDB
from .molecule.pdbx import BCIF, CIF
from .molecule.sdf import SDF
from .molecule.ui import MN_OT_Import_wwPDB, fetch, load_local
from .molecule.ui import fetch, load_local
from .trajectory.trajectory import Trajectory

CLASSES = (
Expand All @@ -16,7 +16,6 @@
MN_OT_Import_Map,
MN_OT_Import_OxDNA_Trajectory,
MN_OT_Import_Star_File,
MN_OT_Import_wwPDB,
]
+ trajectory.CLASSES
+ molecule.CLASSES
Expand Down
15 changes: 9 additions & 6 deletions molecularnodes/entities/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def __init__(self, message):
class MolecularEntity(metaclass=ABCMeta):
def __init__(self) -> None:
self.uuid: str = str(uuid1())
self.object_ref: bpy.types.Object | None
self._object: bpy.types.Object | None
self.type: str = ""

@property
Expand Down Expand Up @@ -45,24 +45,27 @@ def object(self) -> bpy.types.Object | None:
# if the connection is broken then trying to the name will raise a connection
# error. If we are loading from a saved session then the object_ref will be
# None and get an AttributeError
self.object_ref.name
return self.object_ref
self._object.name
return self._object
except (ReferenceError, AttributeError):
for obj in bpy.data.objects:
if obj.mn.uuid == self.uuid:
print(
Warning(
f"Lost connection to object: {self.object_ref}, now connected to {obj}"
f"Lost connection to object: {self._object}, now connected to {obj}"
)
)
self.object_ref = obj
self._object = obj
return obj

return None

@object.setter
def object(self, value):
self.object_ref = value
if isinstance(value, bpy.types.Object) or value is None:
self._object = value
else:
raise TypeError(f"The `object` must be a Blender object, not {value=}")

def named_attribute(self, name="position", evaluate=False) -> np.ndarray | None:
"""
Expand Down
10 changes: 9 additions & 1 deletion molecularnodes/entities/trajectory/trajectory.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from ... import data
from ..entity import MolecularEntity, ObjectMissingError
from ...blender import coll, mesh, nodes
from ...blender import coll, mesh, nodes, path_resolve
from ...utils import lerp, correct_periodic_positions
from .selections import Selection, TrajectorySelectionItem

Expand Down Expand Up @@ -416,6 +416,13 @@ def _attributes_2_blender(self):
},
}

def save_filepaths_on_object(self) -> None:
obj = self.object
obj.mn.filepath_topology = str(path_resolve(self.universe.filename))
obj.mn.filepath_trajectory = str(
path_resolve(self.universe.trajectory.filename)
)

def create_object(
self,
style: str = "vdw",
Expand Down Expand Up @@ -447,6 +454,7 @@ def create_object(
obj["atom_type_unique"] = self.atom_type_unique
self.subframes = subframes
obj.mn.molecule_type = "md"
self.save_filepaths_on_object()

if style is not None:
nodes.create_starting_node_tree(obj, style=style, name=f"MN_{obj.name}")
Expand Down
Loading

0 comments on commit 8fbc753

Please sign in to comment.