molpy.builder¶
Convenience exports for the builder subpackage.
The legacy PolymerBuilder class and bulk builders have been removed in
favour of the new declarative API documented in
notebooks/reacter_polymerbuilder_integration.ipynb.
AutoConnector ¶
Bases: Connector
BigSMILES-guided automatic port selection.
Strategy: 1. If left has port with role='right' and right has role='left' → use those 2. Else if each side has exactly one unconsumed port → use that pair 3. Else raise AmbiguousPortsError
This implements the common case where: - BigSMILES uses [<] for "left" role and [>] for "right" role - We connect left's "right" port to right's "left" port
select_ports ¶
select_ports(left, right, left_ports, right_ports, ctx)
Select ports using BigSMILES role heuristics.
Source code in src/molpy/builder/polymer/connectors.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | |
BlockRegion ¶
BlockRegion(xmin, xmax, ymin, ymax, zmin, zmax, coord_system='lattice')
Bases: Region
Axis-aligned box region
Define a box region specified by x, y, z ranges.
Parameters¶
xmin, xmax : float x-direction range [xmin, xmax] ymin, ymax : float y-direction range [ymin, ymax] zmin, zmax : float z-direction range [zmin, zmax] coord_system : CoordSystem, optional Coordinate system, default is "lattice"
Examples¶
Region in lattice coordinates¶
region = BlockRegion(0, 10, 0, 10, 0, 10, coord_system="lattice")
Region in Cartesian coordinates¶
region = BlockRegion(0, 30, 0, 30, 0, 30, coord_system="cartesian")
Initialize box region
Parameters¶
xmin, xmax : float x-direction range ymin, ymax : float y-direction range zmin, zmax : float z-direction range coord_system : CoordSystem, optional Coordinate system
Source code in src/molpy/builder/crystal.py
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 | |
contains_mask ¶
contains_mask(points)
Check if points are in the box (vectorized)
Parameters¶
points : np.ndarray Point coordinates array of shape (N, 3)
Returns¶
np.ndarray Boolean array of shape (N,)
Examples¶
region = BlockRegion(0, 10, 0, 10, 0, 10) points = np.array([[5, 5, 5], [15, 5, 5]]) mask = region.contains_mask(points) print(mask) # [True, False]
Source code in src/molpy/builder/crystal.py
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 | |
CallbackConnector ¶
CallbackConnector(fn)
Bases: Connector
User-defined callback for port selection.
Example
def my_selector(left, right, left_ports, right_ports, ctx): # Custom logic here return ("port_out", "port_in", "-")
connector = CallbackConnector(my_selector)
Initialize callback connector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
fn
|
Callable[[Monomer, Monomer, Mapping[str, Port], Mapping[str, Port], ConnectorContext], tuple[str, str] | tuple[str, str, BondKind]]
|
Callable that takes (left, right, left_ports, right_ports, ctx) and returns (left_port, right_port [, bond_kind]) |
required |
Source code in src/molpy/builder/polymer/connectors.py
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | |
select_ports ¶
select_ports(left, right, left_ports, right_ports, ctx)
Select ports using user callback.
Source code in src/molpy/builder/polymer/connectors.py
230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | |
ChainConnector ¶
ChainConnector(connectors)
Bases: Connector
Try a list of connectors in order; first one that succeeds wins.
Example
connector = ChainConnector([ TableConnector(specific_rules), AutoConnector(), ])
Initialize chain connector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
connectors
|
Iterable[Connector]
|
List of connectors to try in order |
required |
Source code in src/molpy/builder/polymer/connectors.py
259 260 261 262 263 264 265 266 | |
select_ports ¶
select_ports(left, right, left_ports, right_ports, ctx)
Try connectors in order until one succeeds.
Source code in src/molpy/builder/polymer/connectors.py
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | |
Connector ¶
Abstract base for port selection between two adjacent monomers.
This is topology-only: connectors decide WHICH ports to connect, not HOW to position them geometrically.
select_ports ¶
select_ports(left, right, left_ports, right_ports, ctx)
Select which ports to connect between left and right monomers.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left
|
Monomer
|
Left monomer in the sequence |
required |
right
|
Monomer
|
Right monomer in the sequence |
required |
left_ports
|
Mapping[str, Port]
|
Available (unconsumed) ports on left monomer |
required |
right_ports
|
Mapping[str, Port]
|
Available (unconsumed) ports on right monomer |
required |
ctx
|
ConnectorContext
|
Shared context with step info, sequence, etc. |
required |
Returns:
| Type | Description |
|---|---|
tuple[str, str, BondKind | None]
|
Tuple of (left_port_name, right_port_name, optional_bond_kind_override) |
Raises:
| Type | Description |
|---|---|
AmbiguousPortsError
|
Cannot uniquely determine ports |
NoCompatiblePortsError
|
No valid port pair found |
MissingConnectorRule
|
Required rule not found (TableConnector) |
Source code in src/molpy/builder/polymer/connectors.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | |
ConnectorContext ¶
Bases: dict[str, Any]
Shared context passed to connectors during linear build.
Contains information like: - step: int (current connection step index) - sequence: str (full sequence being built) - left_label: str (label of left monomer) - right_label: str (label of right monomer) - audit: list (accumulated connection records)
CrystalBuilder ¶
CrystalBuilder(lattice)
Crystal structure builder
Efficiently generate crystal structures using NumPy vectorized operations. Supports tiling lattices and creating atoms in specified regions.
Parameters¶
lattice : Lattice Lattice definition to use
Examples¶
Create a simple FCC structure¶
lat = Lattice.cubic_fcc(a=3.52, species="Ni") region = BlockRegion(0, 10, 0, 10, 0, 10, coord_system="lattice") builder = CrystalBuilder(lat) structure = builder.build_block(region) print(len(structure.atoms))
Initialize crystal builder
Parameters¶
lattice : Lattice Lattice definition
Source code in src/molpy/builder/crystal.py
503 504 505 506 507 508 509 510 511 512 | |
build_block ¶
build_block(region, *, i_range=None, j_range=None, k_range=None)
Build crystal structure within a box region
This method efficiently generates crystal structures using vectorized operations: 1. Determine cell index ranges to tile 2. Use NumPy meshgrid and broadcasting to generate all atom positions 3. Apply region filtering 4. Create and return Atomistic structure
Parameters¶
region : BlockRegion Box defining the region for atom generation i_range, j_range, k_range : range | None, optional Explicitly specify cell index ranges. If not provided: - For "lattice" coordinate system: inferred from region boundaries - For "cartesian" coordinate system: must be provided, otherwise raises error
Returns¶
Atomistic Generated crystal structure containing atoms and box information
Raises¶
ValueError If coord_system == "cartesian" and explicit ranges are not provided
Examples¶
Using lattice coordinates (auto-infer ranges)¶
lat = Lattice.cubic_sc(a=2.0, species="Cu") region = BlockRegion(0, 10, 0, 10, 0, 10, coord_system="lattice") builder = CrystalBuilder(lat) structure = builder.build_block(region)
Using explicit ranges¶
structure = builder.build_block( ... region, ... i_range=range(0, 5), ... j_range=range(0, 5), ... k_range=range(0, 5) ... )
Cartesian coordinates (must provide ranges)¶
region_cart = BlockRegion(0, 20, 0, 20, 0, 20, coord_system="cartesian") structure = builder.build_block( ... region_cart, ... i_range=range(0, 10), ... j_range=range(0, 10), ... k_range=range(0, 10) ... )
Notes¶
- This method uses no Python loops, fully based on NumPy vectorized operations
- Generated structure contains:
- Atom positions (Cartesian coordinates)
- Atom species
- Box information (lattice vectors)
- For empty basis (no basis sites), returns empty Atomistic structure
Source code in src/molpy/builder/crystal.py
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 | |
Lattice ¶
Lattice(a1, a2, a3, basis)
Bravais lattice with basis sites.
This class defines a crystal lattice structure, including lattice vectors and basis sites. Lattice vectors define the shape and size of the unit cell, while basis sites define the positions of atoms within the cell (in fractional coordinates).
Parameters¶
a1, a2, a3 : np.ndarray Lattice vectors, each is a NumPy array of shape (3,) basis : list[Site] List of basis sites in fractional coordinates
Attributes¶
a1, a2, a3 : np.ndarray Lattice vectors basis : list[Site] List of basis sites
Examples¶
Create simple cubic lattice¶
lat = Lattice.cubic_sc(a=2.0, species="Cu")
Create face-centered cubic lattice¶
lat = Lattice.cubic_fcc(a=3.52, species="Ni")
Create rocksalt structure¶
lat = Lattice.rocksalt(a=5.64, species_a="Na", species_b="Cl")
Initialize lattice
Parameters¶
a1, a2, a3 : np.ndarray Lattice vectors of shape (3,) basis : list[Site] List of basis sites
Source code in src/molpy/builder/crystal.py
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | |
cell
property
¶
cell
Return 3×3 cell matrix with lattice vectors as rows
Returns¶
np.ndarray Matrix of shape (3, 3), each row is a lattice vector [a1; a2; a3]
add_site ¶
add_site(site)
Add a basis site
Parameters¶
site : Site Basis site to add
Source code in src/molpy/builder/crystal.py
132 133 134 135 136 137 138 139 140 141 | |
cubic_bcc
classmethod
¶
cubic_bcc(a, species)
Create body-centered cubic (Body-Centered Cubic, BCC) lattice
Body-centered cubic lattice has two atoms per unit cell: one at corner and one at body center.
Parameters¶
a : float Lattice constant (in Å) species : str Atomic species (e.g., "Fe", "W")
Returns¶
Lattice Body-centered cubic lattice
Examples¶
lat = Lattice.cubic_bcc(a=3.0, species="Fe") print(len(lat.basis)) # 2
Source code in src/molpy/builder/crystal.py
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 | |
cubic_fcc
classmethod
¶
cubic_fcc(a, species)
Create face-centered cubic (Face-Centered Cubic, FCC) lattice
Face-centered cubic lattice has four atoms per unit cell: one at corner and one at each face center.
Parameters¶
a : float Lattice constant (in Å) species : str Atomic species (e.g., "Ni", "Cu", "Al")
Returns¶
Lattice Face-centered cubic lattice
Examples¶
lat = Lattice.cubic_fcc(a=3.52, species="Ni") print(len(lat.basis)) # 4
Source code in src/molpy/builder/crystal.py
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 | |
cubic_sc
classmethod
¶
cubic_sc(a, species)
Create simple cubic (Simple Cubic, SC) lattice
Simple cubic lattice is the simplest lattice type with one atom per unit cell.
Parameters¶
a : float Lattice constant (in Å) species : str Atomic species (e.g., "Cu", "Fe")
Returns¶
Lattice Simple cubic lattice
Examples¶
lat = Lattice.cubic_sc(a=2.0, species="Cu") print(len(lat.basis)) # 1
Source code in src/molpy/builder/crystal.py
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | |
frac_to_cart ¶
frac_to_cart(frac)
Convert fractional coordinates to Cartesian coordinates
Fractional coordinates (u, v, w) represent position relative to lattice vectors: cart = ua1 + va2 + w*a3 = frac @ cell
Parameters¶
frac : np.ndarray Fractional coordinates of shape (N, 3) or (3,), containing (u, v, w) values
Returns¶
np.ndarray Cartesian coordinates, same shape as input
Examples¶
lat = Lattice.cubic_sc(a=2.0, species="Cu") frac = np.array([0.5, 0.5, 0.5]) cart = lat.frac_to_cart(frac) print(cart) # [1.0, 1.0, 1.0]
Source code in src/molpy/builder/crystal.py
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | |
rocksalt
classmethod
¶
rocksalt(a, species_a, species_b)
Create rocksalt (NaCl) structure
Rocksalt structure consists of two interpenetrating FCC sublattices. Each unit cell contains 4 A atoms and 4 B atoms.
Parameters¶
a : float Lattice constant (in Å) species_a : str First atomic species (e.g., "Na") species_b : str Second atomic species (e.g., "Cl")
Returns¶
Lattice Rocksalt structure lattice
Examples¶
lat = Lattice.rocksalt(a=5.64, species_a="Na", species_b="Cl") print(len(lat.basis)) # 8
Source code in src/molpy/builder/crystal.py
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | |
ReacterConnector ¶
ReacterConnector(default, port_map, overrides=None)
Bases: Connector
Connector that uses chemical reactions (Reacter) for polymer assembly.
This connector integrates port selection and chemical reaction execution. It manages multiple Reacter instances and port mapping strategies for different monomer pairs.
Port Selection Strategy:
Port selection is handled via a port_strategy which must be one of:
1. Callable: Custom function (left, right, left_ports, right_ports, ctx) -> (port_L, port_R)
2. Dict: Explicit mapping {('A','B'): ('1','2'), ...}
There is NO 'auto' mode - port selection must be explicit via port_map.
Attributes:
| Name | Type | Description |
|---|---|---|
default |
Default Reacter for most connections |
|
overrides |
Dict mapping (left_type, right_type) -> specialized Reacter |
|
port_map |
Dict mapping (left_type, right_type) -> (port_L, port_R) |
Example
from molpy.reacter import Reacter from molpy.reacter.selectors import port_anchor_selector, remove_one_H from molpy.reacter.transformers import make_single_bond
default_reacter = Reacter( ... name="C-C_coupling", ... anchor_left=port_anchor_selector, ... anchor_right=port_anchor_selector, ... leaving_left=remove_one_H, ... leaving_right=remove_one_H, ... bond_maker=make_single_bond, ... )
Explicit port mapping for all monomer pairs¶
connector = ReacterConnector( ... default=default_reacter, ... port_map={ ... ('A', 'B'): ('port_1', 'port_2'), ... ('B', 'C'): ('port_3', 'port_4'), ... }, ... overrides={('B', 'C'): special_reacter}, ... )
Initialize ReacterConnector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
default
|
Reacter
|
Default Reacter for most connections |
required |
port_map
|
dict[tuple[str, str], tuple[str, str]]
|
Mapping from (left_type, right_type) to (port_L, port_R) |
required |
overrides
|
dict[tuple[str, str], Reacter] | None
|
Optional mapping from (left_type, right_type) to specialized Reacter instances |
None
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If port_map is not a dict |
Source code in src/molpy/builder/polymer/connectors.py
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 | |
connect ¶
connect(left, right, left_type, right_type, port_L, port_R)
Execute chemical reaction between two monomers.
This method performs the full chemical reaction including: 1. Selecting appropriate reacter based on monomer types 2. Executing reaction (merging, bond making, removing leaving groups) 3. Computing new topology (angles, dihedrals) 4. Collecting metadata for retypification
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left
|
Monomer
|
Left monomer |
required |
right
|
Monomer
|
Right monomer |
required |
left_type
|
str
|
Type label of left monomer |
required |
right_type
|
str
|
Type label of right monomer |
required |
port_L
|
str
|
Port name on left monomer |
required |
port_R
|
str
|
Port name on right monomer |
required |
Returns:
| Type | Description |
|---|---|
Atomistic
|
Tuple of (assembly, metadata) where: |
dict[str, Any]
|
|
tuple[Atomistic, dict[str, Any]]
|
|
Source code in src/molpy/builder/polymer/connectors.py
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 | |
get_all_modified_atoms ¶
get_all_modified_atoms()
Get all atoms modified across all reactions.
Source code in src/molpy/builder/polymer/connectors.py
507 508 509 510 511 512 | |
get_history ¶
get_history()
Get all reaction history (list of ProductSet).
Source code in src/molpy/builder/polymer/connectors.py
503 504 505 | |
get_reacter ¶
get_reacter(left_type, right_type)
Get appropriate reacter for a monomer pair.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left_type
|
str
|
Type label of left monomer (e.g., 'A', 'B') |
required |
right_type
|
str
|
Type label of right monomer |
required |
Returns:
| Type | Description |
|---|---|
Reacter
|
The appropriate Reacter (override if exists, else default) |
Source code in src/molpy/builder/polymer/connectors.py
368 369 370 371 372 373 374 375 376 377 378 379 380 | |
needs_retypification ¶
needs_retypification()
Check if any reactions require retypification.
Source code in src/molpy/builder/polymer/connectors.py
514 515 516 | |
select_ports ¶
select_ports(left, right, left_ports, right_ports, ctx)
Select ports using the configured port_map.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
left
|
Monomer
|
Left monomer |
required |
right
|
Monomer
|
Right monomer |
required |
left_ports
|
Mapping[str, Port]
|
Available ports on left |
required |
right_ports
|
Mapping[str, Port]
|
Available ports on right |
required |
ctx
|
ConnectorContext
|
Connector context with monomer type information |
required |
Returns:
| Type | Description |
|---|---|
tuple[str, str, BondKind | None]
|
Tuple of (port_L, port_R, None) |
Raises:
| Type | Description |
|---|---|
ValueError
|
If port mapping not found or ports invalid |
Source code in src/molpy/builder/polymer/connectors.py
382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 | |
Region ¶
Region(coord_system='lattice')
Bases: ABC
Abstract geometric region class
Define a spatial region that can be represented in lattice or Cartesian coordinates.
Parameters¶
coord_system : CoordSystem Coordinate system, "lattice" or "cartesian" - "lattice": point coordinates in lattice units - "cartesian": point coordinates in Cartesian coordinates (Å)
Notes¶
Subclasses must implement contains_mask method using NumPy
vectorized operations to efficiently check if multiple points are in the region.
Initialize region
Parameters¶
coord_system : CoordSystem, optional Coordinate system, default is "lattice"
Source code in src/molpy/builder/crystal.py
346 347 348 349 350 351 352 353 354 355 | |
contains_mask
abstractmethod
¶
contains_mask(points)
Check if points are in the region (vectorized)
Parameters¶
points : np.ndarray Point coordinates array of shape (N, 3)
Returns¶
np.ndarray Boolean array of shape (N,), True indicates point is in region
Notes¶
- If coord_system == "lattice": points are in lattice units
- If coord_system == "cartesian": points are in Cartesian coordinates
- Must use vectorized operations, no Python loops
Source code in src/molpy/builder/crystal.py
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | |
Site
dataclass
¶
Site(label, species, frac, charge=0.0, meta=None)
Lattice basis site in fractional coordinates.
Attributes¶
label : str Site identifier or name (e.g., "A", "B1") species : str Chemical species or type name (e.g., "Ni", "Na", "Cl") frac : tuple[float, float, float] Fractional coordinates (u, v, w) relative to the Bravais cell, typically in [0, 1) charge : float, optional Charge, default is 0.0 meta : dict[str, Any] | None, optional Optional metadata dictionary
Examples¶
site = Site(label="A", species="Cu", frac=(0.0, 0.0, 0.0)) site_charged = Site(label="Na", species="Na", frac=(0.0, 0.0, 0.0), charge=1.0)
TableConnector ¶
TableConnector(rules, fallback=None)
Bases: Connector
Rule-based port selection using a lookup table.
Maps (left_label, right_label) → (left_port, right_port [, bond_kind])
Example
rules = { ("A", "B"): ("1", "2"), ("B", "A"): ("3", "1", "="), # with bond kind override ("T", "A"): ("t", "1"), } connector = TableConnector(rules, fallback=AutoConnector())
Initialize table connector.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rules
|
Mapping[tuple[str, str], tuple[str, str] | tuple[str, str, BondKind]]
|
Mapping from (left_label, right_label) to port specifications |
required |
fallback
|
Connector | None
|
Optional connector to try if pair not in rules |
None
|
Source code in src/molpy/builder/polymer/connectors.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | |
select_ports ¶
select_ports(left, right, left_ports, right_ports, ctx)
Select ports using table lookup.
Source code in src/molpy/builder/polymer/connectors.py
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | |