Skip to main content

Modular modeling framework for scientific modeling and prototyping.

Project description

GitHub version PyPI version shields.io PyPI pyversions Unittests DOI

mmodel is a lightweight and modular model-building framework for small-scale and nonlinear models. The package aims to solve scientific program prototyping and distribution difficulties, making it easier to create modular, fast, and user-friendly packages.

For using mmodel in a complex scientific workflow, please refer to the mrfmsim on how mmodel improves the development of magnetic resonance force microscopy (MRFM) experiments.

Quickstart

To create a nonlinear model that has the result of (x + y)log(x + y, base):

import math
import numpy as np

def func(sum_xy, log_xy):
    """Function that adds a value to the multiplied inputs."""

    return sum_xy * log_xy + 6

The graph is defined using grouped edges (the NetworkX syntax of edge the definition also works.)

from mmodel import Graph, Model, Node, MemHandler
# create graph edges
grouped_edges = [
    ("add", ["log", "function node"]),
    ("log", "function node"),
]

To add node objects to each node we can use the add_node method from the NetworkX graph class. mmodel provides a way to add a node object to each node with the Node class. The class takes the node name, function, positional inputs, keyword inputs, output, and modifiers as arguments.

Particularly, the positional inputs and keyword inputs are used to replace the original function inputs if necessary. The inputs are given as lists.

The node object can be added to the graph using the add_node_object. The add_node_objects_from method is used for multiple nodes.

# define node objects
node_objects = [
    Node("add", np.add, inputs=["x", "y"], output="sum_xy"),
    Node("log", math.log, inputs=["sum_xy", "log_base"], output="log_xy"),
    Node("function node", func, output="result"),
]

G = Graph(name="example_graph")
G.add_node_objects_from(node_objects)
G.add_grouped_edges_from(grouped_edges)

To define the model, the name, graph, and handler need to be specified. Additional parameters include modifiers, descriptions, and returns lists. The input parameters of the model are determined based on the node function parameter signature, or custom signature can be provided using the inputs parameter.

example_model = Model("example_model", G, handler=MemHandler, doc="Test model.")

The model behaves like a Python function with additional metadata. The graph can be plotted using the visualize method.

# model representation
>>> example_model
<mmodel.model.Model 'example_model'>

>>> print(example_model)
example_model(log_base, x, y)
returns: result
graph: example_graph
handler: MemHandler

Test model.

>>> example_model(2, 5, 3) # (5 + 3)log(5 + 3, 2) + 6
30.0

>>> example_model.visualize()

The resulting graph contains the model metadata and detailed node information.

One key feature of mmodel that differs from other workflows is modifiers, which modify callables post-definition. Modifiers work on both the node level and model level.

Example: Use loop_input modifier on the graph to loop the nodes that require the “log_base” parameter.

from mmodel.modifier import loop_input

H = G.subgraph(inputs=["log_base"])
H.name = "example_subgraph"
loop_node = Model("submodel", H, handler=MemHandler)

looped_G = G.replace_subgraph(
    H,
    Node("loop_node", loop_node, output="looped_z", modifiers=[loop_input("log_base")]),
)
looped_G.name = "looped_graph"

looped_model = Model("looped_model", looped_G, loop_node.handler)

>>> print(looped_model)
looped_model(log_base, x, y)
returns: looped_z
graph: looped_graph
handler: MemHandler

>>> print(looped_model.get_node_object("loop_node"))
loop_node

submodel(log_base, sum_xy)
return: looped_z
functype: mmodel.model.Model
modifiers:
- loop_input(parameter='log_base')

>>> looped_model([2, 4], 5, 3) # (5 + 3)log(5 + 3, 2) + 6
[30.0, 18.0]

The above process is included in the shortcut module and we can use the loop_shortcut to directly apply the above process. Note that the shortcut changes the input parameter name to (name)_loop to distinguish between the models.

from mmodel.shortcut import loop_shortcut
looped_model = loop_shortcut(example_model, "log_base", name="looped_model")

>>> print(looped_model)
looped_model(log_base_loop, x, y)
returns: result
graph: example_graph
handler: MemHandler

Test model.

>>> looped_model([2, 4], 5, 3) # (5 + 3)log(5 + 3, 2) + 6
[30.0, 18.0]

We can use the visualize method to draw the graph. For a graph, a simple diagram with only node names shown, and for a model, the diagram shows detailed node and model information. Customized plotting objects can be created using the Visualizer class.

G.visualize()
# draw the graph and output to a pdf file
example_model.visualize(outfile="example.pdf")

Installation

Graphviz installation

To view the graph, Graphviz needs to be installed: Graphviz Installation For Windows installation, please choose “add Graphviz to the system PATH for all users/current users” during the setup.

For macOS systems, sometimes brew install results in an unexpected installation path, it is recommended to install with conda:

conda install -c conda-forge pygraphviz

MModel installation

pip install mmodel

Development installation

MModel uses poetry as the build system. The package works with both pip and poetry installation.

To install dependencies for “test” and “docs”:

pip install .[test] .[docs]

To run the tests in different Python environments and cases (py310, py311, coverage and docs):

tox

To create the documentation, run under the “/docs” directory:

make html

Citing mmodel

The work was published in the Journal of Chemical Physics.

BibTex:

@article{Sun2023jul,
  title = {mmodel: A Workflow Framework to Accelerate the Development of Experimental Simulations},
  author = {Sun, Peter and Marohn, John A.},
  year = {2023},
  month = {Jul},
  journal = {The Journal of Chemical Physics},
  volume = {159},
  number = {4},
  pages = {044801},
  doi = {10.1063/5.0155617},
  url = {https://pubs.aip.org/jcp/article/159/4/044801/2904249/mmodel-A-workflow-framework-to-accelerate-the}
}

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mmodel-0.9.0.tar.gz (26.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mmodel-0.9.0-py3-none-any.whl (27.9 kB view details)

Uploaded Python 3

File details

Details for the file mmodel-0.9.0.tar.gz.

File metadata

  • Download URL: mmodel-0.9.0.tar.gz
  • Upload date:
  • Size: 26.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.4.0 CPython/3.9.15 Darwin/25.0.0

File hashes

Hashes for mmodel-0.9.0.tar.gz
Algorithm Hash digest
SHA256 9ca84c4aea18bd1565a54cc5acfc31f643251d9cc29388b694471ed97f9e9bfc
MD5 058c663feb8f3cb8e46f4355c4c91f74
BLAKE2b-256 563aed9afa80161108f79aab8975780d433607e023aac404b8096ca90216ef06

See more details on using hashes here.

File details

Details for the file mmodel-0.9.0-py3-none-any.whl.

File metadata

  • Download URL: mmodel-0.9.0-py3-none-any.whl
  • Upload date:
  • Size: 27.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.4.0 CPython/3.9.15 Darwin/25.0.0

File hashes

Hashes for mmodel-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b2bda9c658b244af9474914141fdfcba36962fb07bf4520200e9d8e3e459f99f
MD5 cea3e5f88c88dfb0e6cb86aaa3caafdd
BLAKE2b-256 fe3c4c2cae903d521e4ec225d89e284e1fd4f951ec707ff499d2ce56def86251

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page