novomd 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
novomd-1.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 QuantNexus AI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
novomd-1.2.0/PKG-INFO ADDED
@@ -0,0 +1,311 @@
1
+ Metadata-Version: 2.4
2
+ Name: novomd
3
+ Version: 1.2.0
4
+ Summary: Local-first molecular property calculator. Compute descriptors from SMILES with no server and no API key.
5
+ Author: NovoMCP
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/realariharrison/NovoMD
8
+ Project-URL: Documentation, https://github.com/realariharrison/NovoMD#readme
9
+ Project-URL: Repository, https://github.com/realariharrison/NovoMD.git
10
+ Project-URL: Issues, https://github.com/realariharrison/NovoMD/issues
11
+ Keywords: molecular-dynamics,computational-chemistry,cheminformatics,molecular-descriptors,smiles,openmd,rdkit,local-first
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: OS Independent
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Scientific/Engineering :: Chemistry
22
+ Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
23
+ Classifier: Framework :: FastAPI
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: numpy<2.0.0,>=1.24.0
28
+ Requires-Dist: scipy>=1.11.0
29
+ Requires-Dist: rdkit>=2023.3.1
30
+ Provides-Extra: server
31
+ Requires-Dist: fastapi>=0.104.0; extra == "server"
32
+ Requires-Dist: uvicorn[standard]>=0.24.0; extra == "server"
33
+ Requires-Dist: pydantic>=2.5.0; extra == "server"
34
+ Requires-Dist: pydantic-settings>=2.1.0; extra == "server"
35
+ Requires-Dist: python-dotenv>=1.0.0; extra == "server"
36
+ Requires-Dist: slowapi>=0.1.9; extra == "server"
37
+ Provides-Extra: dev
38
+ Requires-Dist: pytest>=7.4.0; extra == "dev"
39
+ Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
40
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
41
+ Requires-Dist: httpx>=0.25.0; extra == "dev"
42
+ Requires-Dist: flake8>=6.1.0; extra == "dev"
43
+ Requires-Dist: black>=23.9.0; extra == "dev"
44
+ Requires-Dist: isort>=5.12.0; extra == "dev"
45
+ Requires-Dist: mypy>=1.5.0; extra == "dev"
46
+ Requires-Dist: bandit>=1.7.0; extra == "dev"
47
+ Requires-Dist: safety>=2.3.0; extra == "dev"
48
+ Requires-Dist: pre-commit>=3.4.0; extra == "dev"
49
+ Dynamic: license-file
50
+
51
+ <div align="center">
52
+
53
+ <img src="docs/novomd-card.png" alt="NovoMD: local-first molecular property calculation" width="820" />
54
+
55
+ # NovoMD
56
+
57
+ **local-first molecular property calculation**
58
+
59
+ [![CI](https://github.com/realariharrison/NovoMD/actions/workflows/ci.yml/badge.svg)](https://github.com/realariharrison/NovoMD/actions/workflows/ci.yml)
60
+ [![License: MIT](https://img.shields.io/badge/License-MIT-B8704B.svg)](LICENSE)
61
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-2D2A26.svg)](https://www.python.org/downloads/)
62
+
63
+ </div>
64
+
65
+ NovoMD turns a SMILES string into a set of molecular descriptors. It runs on your own machine, with no account and no API key. Install it as a Python library, call it from the command line, or run it as a REST service.
66
+
67
+ ## What it is, and what it is not
68
+
69
+ NovoMD computes 32+ outcome-level descriptors from a 3D conformer: geometry, an energy estimate, electrostatics, surface and volume, atom counts, and the coordinates for visualization. The calculation is local and deterministic.
70
+
71
+ It does not run full molecular dynamics trajectories, docking, binding affinity, or ADMET. The scope is deliberate. For that work, see [Beyond property calculation](#beyond-property-calculation) below.
72
+
73
+ ## Quick start
74
+
75
+ ### Python library
76
+
77
+ The shortest path. No server, no key.
78
+
79
+ ```bash
80
+ pip install novomd
81
+ ```
82
+
83
+ ```python
84
+ from novomd import calculate_properties
85
+
86
+ props = calculate_properties("CCO")
87
+ print(props["molecular_weight"]) # 46.07
88
+ print(props["radius_of_gyration"])
89
+ ```
90
+
91
+ Process a list in one call. A bad SMILES does not stop the batch; each item carries its own status.
92
+
93
+ ```python
94
+ from novomd import calculate_properties_batch
95
+
96
+ results = calculate_properties_batch(["CCO", "CC(=O)O", "NOT_VALID"])
97
+ for item in results:
98
+ if item["status"] == "ok":
99
+ print(item["smiles"], item["properties"]["molecular_weight"])
100
+ else:
101
+ print(item["smiles"], "->", item["error"])
102
+ ```
103
+
104
+ RDKit, NumPy, and SciPy install automatically. Everything runs on your hardware.
105
+
106
+ ### Command line
107
+
108
+ ```bash
109
+ novomd props "CCO"
110
+ novomd props "CC(=O)OC1=CC=CC=C1C(=O)O" --compact
111
+ novomd batch molecules.smi --out results.csv
112
+ ```
113
+
114
+ `batch` reads a `.smi` file (one SMILES per line) and writes a CSV, TSV, or JSON table.
115
+
116
+ ### From an AI assistant (MCP)
117
+
118
+ NovoMD exposes a [Model Context Protocol](https://modelcontextprotocol.io/) endpoint, so assistants like Claude can query molecular properties directly.
119
+
120
+ **Endpoint:** `https://quantnexusai-novomd.hf.space/gradio_api/mcp/sse`
121
+
122
+ Add it as a custom connector in Claude (Settings, then Integrations), or point any MCP-compatible client at the same URL. Then ask:
123
+
124
+ - "Calculate the molecular properties of aspirin (CC(=O)OC1=CC=CC=C1C(=O)O)."
125
+ - "What is the dipole moment of caffeine?"
126
+
127
+ The endpoint works with Claude (web and desktop), Cursor, Continue.dev, and any client that speaks the [MCP specification](https://modelcontextprotocol.io/).
128
+
129
+ ### REST service (Docker)
130
+
131
+ For networked or containerized use, run the same core behind FastAPI.
132
+
133
+ ```bash
134
+ # pre-built image
135
+ docker run -d -p 8010:8010 \
136
+ -e NOVOMD_API_KEY="your-secure-api-key" \
137
+ --name novomd \
138
+ ghcr.io/realariharrison/novomd:latest
139
+
140
+ curl http://localhost:8010/health
141
+ ```
142
+
143
+ Or from source:
144
+
145
+ ```bash
146
+ pip install "novomd[server]"
147
+ uvicorn main:app --host 0.0.0.0 --port 8010
148
+ ```
149
+
150
+ ## What you get
151
+
152
+ 32+ descriptors, calculated from an embedded 3D structure:
153
+
154
+ - **Geometry** (7): radius of gyration, asphericity, eccentricity, inertia shape factor, span, principal moments of inertia
155
+ - **Energy** (6): conformer energy, van der Waals, electrostatic, torsion strain, angle strain, optimization delta
156
+ - **Electrostatics** (6): dipole moment, total charge, max and min partial charge, charge span, electrostatic potential
157
+ - **Surface and volume** (4): SASA, molecular volume, globularity, surface-to-volume ratio
158
+ - **Atom counts** (2): total atoms, heavy atoms
159
+ - **Visualization** (5+): full atomic coordinates, atom types, bond connectivity
160
+
161
+ Energy values are estimates from the conformer, not from a force-field simulation. The descriptors are derived from real 3D coordinates, not mocked.
162
+
163
+ ## Library reference
164
+
165
+ ```python
166
+ from novomd import calculate_properties, calculate_properties_batch
167
+
168
+ # one molecule -> descriptor dict
169
+ calculate_properties("CCO", add_hydrogens=True, optimize_3d=True)
170
+
171
+ # many molecules -> list of {smiles, status, properties | error}
172
+ calculate_properties_batch(["CCO", "C"], max_batch_size=1000)
173
+ ```
174
+
175
+ Both raise `InvalidSMILESError` for unparseable input and `RDKitNotAvailableError` if RDKit is missing. The batch function isolates per-item failures instead of raising.
176
+
177
+ ## REST API
178
+
179
+ All endpoints except `/health` require an API key in the `X-API-Key` header.
180
+
181
+ | Endpoint | Method | Description |
182
+ |----------|--------|-------------|
183
+ | `/health` | GET | Health check (no auth) |
184
+ | `/status` | GET | Service status and capabilities |
185
+ | `/smiles-to-omd` | POST | Convert SMILES to OpenMD with 32+ properties |
186
+ | `/batch` | POST | Calculate properties for many SMILES in one call |
187
+ | `/atom2md` | POST | Convert PDB to OpenMD format |
188
+ | `/force-fields` | GET | List available force fields |
189
+ | `/force-field-types/{ff}` | GET | Atom types for a force field |
190
+
191
+ ```bash
192
+ curl -X POST http://localhost:8010/batch \
193
+ -H "Content-Type: application/json" \
194
+ -H "X-API-Key: your-api-key" \
195
+ -d '{"molecules": ["CCO", "CC(=O)O", "NOT_VALID"]}'
196
+ ```
197
+
198
+ ```json
199
+ {
200
+ "count": 3,
201
+ "succeeded": 2,
202
+ "failed": 1,
203
+ "results": [
204
+ {"smiles": "CCO", "status": "ok", "properties": {"molecular_weight": 46.07, "...": "..."}},
205
+ {"smiles": "CC(=O)O", "status": "ok", "properties": {"...": "..."}},
206
+ {"smiles": "NOT_VALID", "status": "error", "error": "Invalid SMILES string: 'NOT_VALID'"}
207
+ ]
208
+ }
209
+ ```
210
+
211
+ Batches are capped at 1,000 molecules per request and share the service rate limit.
212
+
213
+ ### Notebooks
214
+
215
+ | Notebook | Topic |
216
+ |----------|-------|
217
+ | [01_getting_started.ipynb](examples/01_getting_started.ipynb) | Basic usage and conversion |
218
+ | [02_molecular_properties.ipynb](examples/02_molecular_properties.ipynb) | Property analysis with pandas and matplotlib |
219
+ | [03_visualization.ipynb](examples/03_visualization.ipynb) | 3D visualization with plotly and py3Dmol |
220
+ | [04_batch_processing.ipynb](examples/04_batch_processing.ipynb) | One-call batch, library and endpoint |
221
+
222
+ ## Beyond property calculation
223
+
224
+ NovoMD computes molecular descriptors locally. It does not run full MD trajectories, docking, ADMET, or compliance.
225
+
226
+ For those, the same team builds NovoMCP, a computational engine for AI-native discovery: 122M enriched compounds, docking and FEP pipelines, ADMET and compliance scoring, and an immutable audit trail on every step. NovoMD is open and always will be. NovoMCP is the production layer for work that outgrows it.
227
+
228
+ Learn more: [novomcp.com](https://novomcp.com)
229
+
230
+ ## Force fields
231
+
232
+ `AMBER14`, `AMBER99SB`, `CHARMM36`, `OPLS-AA/M`, `GROMOS 54A7`. Property values are conformer-derived and force-field-independent; the force field affects only the OpenMD output.
233
+
234
+ ## Configuration
235
+
236
+ Set these in a `.env` file or as environment variables (REST service only).
237
+
238
+ | Variable | Description | Default |
239
+ |----------|-------------|---------|
240
+ | `NOVOMD_API_KEY` | API authentication key (required) | - |
241
+ | `PORT` | Server port | 8010 |
242
+ | `HOST` | Server host | 0.0.0.0 |
243
+ | `LOG_LEVEL` | DEBUG, INFO, WARNING, ERROR | INFO |
244
+ | `CORS_ORIGINS` | Comma-separated origins, or "*" for all | localhost:3000,localhost:8080 |
245
+ | `RATE_LIMIT` | e.g. "100/minute", "1000/hour" | 100/minute |
246
+
247
+ ## Development
248
+
249
+ ```bash
250
+ pip install -e ".[dev,server]" # core + server + dev tools
251
+ pre-commit install
252
+
253
+ pytest tests/ -v
254
+ pytest tests/ --cov=novomd --cov=main --cov-report=term-missing
255
+
256
+ black . && isort . && flake8 .
257
+ mypy novomd main.py auth.py config.py
258
+ bandit -r . -x ./tests
259
+ ```
260
+
261
+ ```
262
+ NovoMD/
263
+ ├── novomd/ # importable library (framework-free core)
264
+ │ ├── core.py # property calculation
265
+ │ ├── batch.py # batch with per-item error isolation
266
+ │ ├── conversion.py # PDB to OpenMD
267
+ │ ├── cli.py # `novomd` command
268
+ │ └── exceptions.py
269
+ ├── main.py # FastAPI service (imports the core)
270
+ ├── config.py # configuration
271
+ ├── auth.py # API-key authentication
272
+ ├── tests/ # unit + integration tests
273
+ ├── examples/ # Jupyter notebooks
274
+ └── .github/workflows/ # CI and PyPI publish
275
+ ```
276
+
277
+ ## Security
278
+
279
+ NovoMD runs locally by default; no molecular data leaves your machine. For the REST service, use a strong `NOVOMD_API_KEY`, deploy behind TLS, and restrict `CORS_ORIGINS`. To report a vulnerability, see [SECURITY.md](SECURITY.md).
280
+
281
+ ## Contributing
282
+
283
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).
284
+
285
+ - **Issues**: [GitHub Issues](https://github.com/realariharrison/NovoMD/issues)
286
+ - **Discussions**: [GitHub Discussions](https://github.com/realariharrison/NovoMD/discussions)
287
+
288
+ ## License
289
+
290
+ MIT. See [LICENSE](LICENSE).
291
+
292
+ Built with [FastAPI](https://fastapi.tiangolo.com/) and [RDKit](https://www.rdkit.org/).
293
+
294
+ ## Citation
295
+
296
+ ```bibtex
297
+ @software{novomd2025,
298
+ title = {NovoMD: Local-First Molecular Property Calculation},
299
+ author = {NovoMCP},
300
+ year = {2025},
301
+ url = {https://github.com/realariharrison/NovoMD}
302
+ }
303
+ ```
304
+
305
+ ---
306
+
307
+ <div align="center">
308
+
309
+ Built by the NovoMCP team
310
+
311
+ </div>
novomd-1.2.0/README.md ADDED
@@ -0,0 +1,261 @@
1
+ <div align="center">
2
+
3
+ <img src="docs/novomd-card.png" alt="NovoMD: local-first molecular property calculation" width="820" />
4
+
5
+ # NovoMD
6
+
7
+ **local-first molecular property calculation**
8
+
9
+ [![CI](https://github.com/realariharrison/NovoMD/actions/workflows/ci.yml/badge.svg)](https://github.com/realariharrison/NovoMD/actions/workflows/ci.yml)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-B8704B.svg)](LICENSE)
11
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-2D2A26.svg)](https://www.python.org/downloads/)
12
+
13
+ </div>
14
+
15
+ NovoMD turns a SMILES string into a set of molecular descriptors. It runs on your own machine, with no account and no API key. Install it as a Python library, call it from the command line, or run it as a REST service.
16
+
17
+ ## What it is, and what it is not
18
+
19
+ NovoMD computes 32+ outcome-level descriptors from a 3D conformer: geometry, an energy estimate, electrostatics, surface and volume, atom counts, and the coordinates for visualization. The calculation is local and deterministic.
20
+
21
+ It does not run full molecular dynamics trajectories, docking, binding affinity, or ADMET. The scope is deliberate. For that work, see [Beyond property calculation](#beyond-property-calculation) below.
22
+
23
+ ## Quick start
24
+
25
+ ### Python library
26
+
27
+ The shortest path. No server, no key.
28
+
29
+ ```bash
30
+ pip install novomd
31
+ ```
32
+
33
+ ```python
34
+ from novomd import calculate_properties
35
+
36
+ props = calculate_properties("CCO")
37
+ print(props["molecular_weight"]) # 46.07
38
+ print(props["radius_of_gyration"])
39
+ ```
40
+
41
+ Process a list in one call. A bad SMILES does not stop the batch; each item carries its own status.
42
+
43
+ ```python
44
+ from novomd import calculate_properties_batch
45
+
46
+ results = calculate_properties_batch(["CCO", "CC(=O)O", "NOT_VALID"])
47
+ for item in results:
48
+ if item["status"] == "ok":
49
+ print(item["smiles"], item["properties"]["molecular_weight"])
50
+ else:
51
+ print(item["smiles"], "->", item["error"])
52
+ ```
53
+
54
+ RDKit, NumPy, and SciPy install automatically. Everything runs on your hardware.
55
+
56
+ ### Command line
57
+
58
+ ```bash
59
+ novomd props "CCO"
60
+ novomd props "CC(=O)OC1=CC=CC=C1C(=O)O" --compact
61
+ novomd batch molecules.smi --out results.csv
62
+ ```
63
+
64
+ `batch` reads a `.smi` file (one SMILES per line) and writes a CSV, TSV, or JSON table.
65
+
66
+ ### From an AI assistant (MCP)
67
+
68
+ NovoMD exposes a [Model Context Protocol](https://modelcontextprotocol.io/) endpoint, so assistants like Claude can query molecular properties directly.
69
+
70
+ **Endpoint:** `https://quantnexusai-novomd.hf.space/gradio_api/mcp/sse`
71
+
72
+ Add it as a custom connector in Claude (Settings, then Integrations), or point any MCP-compatible client at the same URL. Then ask:
73
+
74
+ - "Calculate the molecular properties of aspirin (CC(=O)OC1=CC=CC=C1C(=O)O)."
75
+ - "What is the dipole moment of caffeine?"
76
+
77
+ The endpoint works with Claude (web and desktop), Cursor, Continue.dev, and any client that speaks the [MCP specification](https://modelcontextprotocol.io/).
78
+
79
+ ### REST service (Docker)
80
+
81
+ For networked or containerized use, run the same core behind FastAPI.
82
+
83
+ ```bash
84
+ # pre-built image
85
+ docker run -d -p 8010:8010 \
86
+ -e NOVOMD_API_KEY="your-secure-api-key" \
87
+ --name novomd \
88
+ ghcr.io/realariharrison/novomd:latest
89
+
90
+ curl http://localhost:8010/health
91
+ ```
92
+
93
+ Or from source:
94
+
95
+ ```bash
96
+ pip install "novomd[server]"
97
+ uvicorn main:app --host 0.0.0.0 --port 8010
98
+ ```
99
+
100
+ ## What you get
101
+
102
+ 32+ descriptors, calculated from an embedded 3D structure:
103
+
104
+ - **Geometry** (7): radius of gyration, asphericity, eccentricity, inertia shape factor, span, principal moments of inertia
105
+ - **Energy** (6): conformer energy, van der Waals, electrostatic, torsion strain, angle strain, optimization delta
106
+ - **Electrostatics** (6): dipole moment, total charge, max and min partial charge, charge span, electrostatic potential
107
+ - **Surface and volume** (4): SASA, molecular volume, globularity, surface-to-volume ratio
108
+ - **Atom counts** (2): total atoms, heavy atoms
109
+ - **Visualization** (5+): full atomic coordinates, atom types, bond connectivity
110
+
111
+ Energy values are estimates from the conformer, not from a force-field simulation. The descriptors are derived from real 3D coordinates, not mocked.
112
+
113
+ ## Library reference
114
+
115
+ ```python
116
+ from novomd import calculate_properties, calculate_properties_batch
117
+
118
+ # one molecule -> descriptor dict
119
+ calculate_properties("CCO", add_hydrogens=True, optimize_3d=True)
120
+
121
+ # many molecules -> list of {smiles, status, properties | error}
122
+ calculate_properties_batch(["CCO", "C"], max_batch_size=1000)
123
+ ```
124
+
125
+ Both raise `InvalidSMILESError` for unparseable input and `RDKitNotAvailableError` if RDKit is missing. The batch function isolates per-item failures instead of raising.
126
+
127
+ ## REST API
128
+
129
+ All endpoints except `/health` require an API key in the `X-API-Key` header.
130
+
131
+ | Endpoint | Method | Description |
132
+ |----------|--------|-------------|
133
+ | `/health` | GET | Health check (no auth) |
134
+ | `/status` | GET | Service status and capabilities |
135
+ | `/smiles-to-omd` | POST | Convert SMILES to OpenMD with 32+ properties |
136
+ | `/batch` | POST | Calculate properties for many SMILES in one call |
137
+ | `/atom2md` | POST | Convert PDB to OpenMD format |
138
+ | `/force-fields` | GET | List available force fields |
139
+ | `/force-field-types/{ff}` | GET | Atom types for a force field |
140
+
141
+ ```bash
142
+ curl -X POST http://localhost:8010/batch \
143
+ -H "Content-Type: application/json" \
144
+ -H "X-API-Key: your-api-key" \
145
+ -d '{"molecules": ["CCO", "CC(=O)O", "NOT_VALID"]}'
146
+ ```
147
+
148
+ ```json
149
+ {
150
+ "count": 3,
151
+ "succeeded": 2,
152
+ "failed": 1,
153
+ "results": [
154
+ {"smiles": "CCO", "status": "ok", "properties": {"molecular_weight": 46.07, "...": "..."}},
155
+ {"smiles": "CC(=O)O", "status": "ok", "properties": {"...": "..."}},
156
+ {"smiles": "NOT_VALID", "status": "error", "error": "Invalid SMILES string: 'NOT_VALID'"}
157
+ ]
158
+ }
159
+ ```
160
+
161
+ Batches are capped at 1,000 molecules per request and share the service rate limit.
162
+
163
+ ### Notebooks
164
+
165
+ | Notebook | Topic |
166
+ |----------|-------|
167
+ | [01_getting_started.ipynb](examples/01_getting_started.ipynb) | Basic usage and conversion |
168
+ | [02_molecular_properties.ipynb](examples/02_molecular_properties.ipynb) | Property analysis with pandas and matplotlib |
169
+ | [03_visualization.ipynb](examples/03_visualization.ipynb) | 3D visualization with plotly and py3Dmol |
170
+ | [04_batch_processing.ipynb](examples/04_batch_processing.ipynb) | One-call batch, library and endpoint |
171
+
172
+ ## Beyond property calculation
173
+
174
+ NovoMD computes molecular descriptors locally. It does not run full MD trajectories, docking, ADMET, or compliance.
175
+
176
+ For those, the same team builds NovoMCP, a computational engine for AI-native discovery: 122M enriched compounds, docking and FEP pipelines, ADMET and compliance scoring, and an immutable audit trail on every step. NovoMD is open and always will be. NovoMCP is the production layer for work that outgrows it.
177
+
178
+ Learn more: [novomcp.com](https://novomcp.com)
179
+
180
+ ## Force fields
181
+
182
+ `AMBER14`, `AMBER99SB`, `CHARMM36`, `OPLS-AA/M`, `GROMOS 54A7`. Property values are conformer-derived and force-field-independent; the force field affects only the OpenMD output.
183
+
184
+ ## Configuration
185
+
186
+ Set these in a `.env` file or as environment variables (REST service only).
187
+
188
+ | Variable | Description | Default |
189
+ |----------|-------------|---------|
190
+ | `NOVOMD_API_KEY` | API authentication key (required) | - |
191
+ | `PORT` | Server port | 8010 |
192
+ | `HOST` | Server host | 0.0.0.0 |
193
+ | `LOG_LEVEL` | DEBUG, INFO, WARNING, ERROR | INFO |
194
+ | `CORS_ORIGINS` | Comma-separated origins, or "*" for all | localhost:3000,localhost:8080 |
195
+ | `RATE_LIMIT` | e.g. "100/minute", "1000/hour" | 100/minute |
196
+
197
+ ## Development
198
+
199
+ ```bash
200
+ pip install -e ".[dev,server]" # core + server + dev tools
201
+ pre-commit install
202
+
203
+ pytest tests/ -v
204
+ pytest tests/ --cov=novomd --cov=main --cov-report=term-missing
205
+
206
+ black . && isort . && flake8 .
207
+ mypy novomd main.py auth.py config.py
208
+ bandit -r . -x ./tests
209
+ ```
210
+
211
+ ```
212
+ NovoMD/
213
+ ├── novomd/ # importable library (framework-free core)
214
+ │ ├── core.py # property calculation
215
+ │ ├── batch.py # batch with per-item error isolation
216
+ │ ├── conversion.py # PDB to OpenMD
217
+ │ ├── cli.py # `novomd` command
218
+ │ └── exceptions.py
219
+ ├── main.py # FastAPI service (imports the core)
220
+ ├── config.py # configuration
221
+ ├── auth.py # API-key authentication
222
+ ├── tests/ # unit + integration tests
223
+ ├── examples/ # Jupyter notebooks
224
+ └── .github/workflows/ # CI and PyPI publish
225
+ ```
226
+
227
+ ## Security
228
+
229
+ NovoMD runs locally by default; no molecular data leaves your machine. For the REST service, use a strong `NOVOMD_API_KEY`, deploy behind TLS, and restrict `CORS_ORIGINS`. To report a vulnerability, see [SECURITY.md](SECURITY.md).
230
+
231
+ ## Contributing
232
+
233
+ Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md).
234
+
235
+ - **Issues**: [GitHub Issues](https://github.com/realariharrison/NovoMD/issues)
236
+ - **Discussions**: [GitHub Discussions](https://github.com/realariharrison/NovoMD/discussions)
237
+
238
+ ## License
239
+
240
+ MIT. See [LICENSE](LICENSE).
241
+
242
+ Built with [FastAPI](https://fastapi.tiangolo.com/) and [RDKit](https://www.rdkit.org/).
243
+
244
+ ## Citation
245
+
246
+ ```bibtex
247
+ @software{novomd2025,
248
+ title = {NovoMD: Local-First Molecular Property Calculation},
249
+ author = {NovoMCP},
250
+ year = {2025},
251
+ url = {https://github.com/realariharrison/NovoMD}
252
+ }
253
+ ```
254
+
255
+ ---
256
+
257
+ <div align="center">
258
+
259
+ Built by the NovoMCP team
260
+
261
+ </div>
@@ -0,0 +1,3 @@
1
+ """Single source of truth for the package version."""
2
+
3
+ __version__ = "1.2.0"
@@ -0,0 +1,42 @@
1
+ """NovoMD: a local-first molecular property calculator.
2
+
3
+ Compute molecular descriptors on your own hardware, no server and no API key::
4
+
5
+ from novomd import calculate_properties
6
+ props = calculate_properties("CCO")
7
+ print(props["molecular_weight"])
8
+
9
+ The same core powers the optional REST service (``pip install novomd[server]``).
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ from .__about__ import __version__
15
+ from .batch import MAX_BATCH_SIZE, calculate_properties_batch
16
+ from .conversion import get_atom_type, pdb_to_omd
17
+ from .core import (
18
+ RDKIT_AVAILABLE,
19
+ calculate_all_molecular_properties,
20
+ calculate_partial_charges,
21
+ calculate_properties,
22
+ extract_coordinates_from_pdb,
23
+ smiles_to_pdb,
24
+ )
25
+ from .exceptions import InvalidSMILESError, NovoMDError, RDKitNotAvailableError
26
+
27
+ __all__ = [
28
+ "__version__",
29
+ "RDKIT_AVAILABLE",
30
+ "calculate_properties",
31
+ "calculate_properties_batch",
32
+ "MAX_BATCH_SIZE",
33
+ "calculate_all_molecular_properties",
34
+ "calculate_partial_charges",
35
+ "extract_coordinates_from_pdb",
36
+ "smiles_to_pdb",
37
+ "get_atom_type",
38
+ "pdb_to_omd",
39
+ "NovoMDError",
40
+ "InvalidSMILESError",
41
+ "RDKitNotAvailableError",
42
+ ]