Solver-based attribute resolver for OpenVCAD.
Project description
pyvcad_attribute_resolver
Solver-based attribute resolution for OpenVCAD models. Automatically converts design-intent attributes (e.g. density, shore hardness) into machine-level attributes (e.g. nozzle temperature, flow-rate multiplier) using registered conversion data.
See the main OpenVCAD package for more info. For a deep-dive into the architecture, see design_doc.md.
Quick Start
import pyvcad as pv
import pyvcad_attribute_resolver as resolver
# Load built-in foaming filament data
resolver.register_foaming_conversions()
# Build a design with a physical attribute
sphere = pv.Sphere(pv.Vec3(0, 0, 0), 10.0)
sphere.set_attribute(pv.DefaultAttributes.TEMPERATURE,
pv.FloatAttribute("x + 210"))
# The resolver figures out: temperature -> flow_rate
result = resolver.adapt(sphere, ["flow_rate"], tags=["foaming_tpu"])
API Reference
| Function | Description |
|---|---|
register_conversion(source, target, converter_factory, ...) |
Register a new conversion edge |
unregister_conversion(name) |
Remove a conversion by name |
list_conversions() |
List all registered ConversionEntry objects |
clear_conversions() |
Remove all registered conversions |
adapt(design, targets, tags=..., ...) |
Wrap a design node with automatic conversions |
list_modules() |
Discover installed domain modules |
register_foaming_conversions() |
Register all 5 foaming filament conversions |
register_tpu_conversions() |
Register VarioShore TPU conversions only |
register_pla_conversions() |
Register LW-PLA conversions only |
register_j750_shore_hardness_conversions() |
Register J750 shore-hardness to volume-fractions conversions |
register_j750_modulus_toughness_conversions() |
Register the J750 modulus+toughness inverse-design conversion |
register_generic_color_conversions(alpha=1.0) |
Register machine-agnostic COLOR_RGB <-> COLOR_RGBA conversions |
generate_j750_modulus_toughness_lookup_table(...) |
Regenerate the bundled J750 inverse lookup table |
generate_j750_modulus_toughness_reachable_region_plot(...) |
Regenerate the J750 reachable-region validation plot |
Adding a New Conversion Module
This section walks through adding your own material data to the resolver.
1. Create the Module Folder
Create a new sub-package under modules/:
resolver/src/pyvcad_attribute_resolver/modules/
└── your_material/
├── __init__.py
└── data.py # or .csv, .json — whatever suits your data
2. Add Your Data
Put your empirical measurements in data.py. Each dataset is a list of
(input_value, output_value) tuples:
# data.py
#: Density (g/cm³) -> temperature (°C)
DENSITY_TO_TEMPERATURE = [
(0.50, 260),
(0.65, 250),
(0.80, 240),
(1.00, 230),
]
#: Temperature (°C) -> flow rate multiplier
TEMPERATURE_TO_FLOW_RATE = [
(230, 1.20),
(240, 1.00),
(250, 0.85),
(260, 0.75),
]
Tip: If your data lives in CSV files, you can load them in
data.pyusingimportlib.resourcesorpathlib.Path(__file__).parentto locate the files relative to the module.
3. Write Registration Functions
In __init__.py, create factory functions and register them:
# __init__.py
import pyvcad as pv
from pyvcad_attribute_resolver.registry import register_conversion
from .data import DENSITY_TO_TEMPERATURE, TEMPERATURE_TO_FLOW_RATE
def _lut_factory(source_attr, target_attr, data):
"""Return a callable that builds a fresh LookupTableConverter."""
entries = [pv.LookupTableEntry(kv[0], kv[0], kv[1]) for kv in data]
def _factory():
return pv.LookupTableConverter(
[source_attr], [target_attr],
entries, pv.InterpolationMode.LINEAR,
)
return _factory
def register_your_material_conversions():
"""Register all conversions for your material."""
register_conversion(
source="density",
target="temperature",
converter_factory=_lut_factory(
pv.DefaultAttributes.DENSITY,
pv.DefaultAttributes.TEMPERATURE,
DENSITY_TO_TEMPERATURE,
),
name="your_material_density_to_temperature",
priority=0,
tags=["your_material"],
)
register_conversion(
source="temperature",
target="flow_rate",
converter_factory=_lut_factory(
pv.DefaultAttributes.TEMPERATURE,
pv.DefaultAttributes.FLOW_RATE,
TEMPERATURE_TO_FLOW_RATE,
),
name="your_material_temperature_to_flow_rate",
priority=0,
tags=["your_material"],
)
Key points:
namemust be globally unique across all modules.tagsshould identify your material so users can filter withtags=["your_material"]. Use distinct tags to avoid ambiguity with other modules that define the same conversion edges.required_inputsshould list every attribute the converter actually consumes. Leave it unset for ordinary one-input conversions; set it explicitly for cases likemodulus + toughness -> volume_fractions.converter_factorymust be a zero-arg callable that returns a new converter instance each time.
J750 Modulus/Toughness Module
The built-in j750_modulus_toughness module inverse-designs
volume_fractions from two design-intent attributes:
modulusin MPatoughnessin MJ/m^3
It uses the legacy C++ model to generate a 128 x 128 lookup table over:
log10(modulus [MPa]) in [-1.0, 3.5]toughness [MJ/m^3] in [0.0, 6.5]
The shipped runtime table assumes the J750 materials are:
Agilus30ClrVeroBlackM.Cleanser
and uses a default maximum cleanser volume fraction of 0.30.
To register the built-in table:
import pyvcad_attribute_resolver as resolver
resolver.register_j750_modulus_toughness_conversions()
To regenerate the lookup table with a different liquid cap or resolution:
resolver.generate_j750_modulus_toughness_lookup_table(
output_path="j750_custom_lut.json",
table_size=192,
max_liquid_volume=0.25,
fail_threshold=0.05,
)
Then register that table explicitly:
resolver.register_j750_modulus_toughness_conversions(
lookup_table_path="j750_custom_lut.json",
)
The generator stores a separate validity mask alongside the fraction grid. Invalid cells represent unreachable modulus/toughness targets; runtime lookup raises immediately instead of clamping to a nearby printable mixture.
4. Wire It Into the Package
Add a convenience re-export in the top-level __init__.py:
# resolver/src/pyvcad_attribute_resolver/__init__.py
from .modules.your_material import register_your_material_conversions
5. Use It
import pyvcad as pv
import pyvcad_attribute_resolver as resolver
resolver.register_your_material_conversions()
design = pv.Sphere(pv.Vec3(0, 0, 0), 10.0)
design.set_attribute(pv.DefaultAttributes.DENSITY,
pv.FloatAttribute(0.7))
# Automatically resolves: density -> temperature -> flow_rate
result = resolver.adapt(design, ["temperature", "flow_rate"],
tags=["your_material"])
6. Add Tests
Create a test file in resolver/tests/ (see test_foaming.py for an example):
# resolver/tests/test_your_material.py
import pytest
import pyvcad as pv
import pyvcad_attribute_resolver as resolver
@pytest.fixture(autouse=True)
def clean():
resolver.clear_conversions()
yield
resolver.clear_conversions()
def test_registration():
resolver.register_your_material_conversions()
names = {e.name for e in resolver.list_conversions()}
assert "your_material_density_to_temperature" in names
assert "your_material_temperature_to_flow_rate" in names
def test_adapt_chain():
resolver.register_your_material_conversions()
sphere = pv.Sphere(pv.Vec3(0, 0, 0), 1.0)
sphere.set_attribute("density", pv.FloatAttribute(0.7))
result = resolver.adapt(sphere,
["temperature", "flow_rate"],
tags=["your_material"])
assert "temperature" in result.attribute_list()
assert "flow_rate" in result.attribute_list()
Run with:
cd resolver && python -m pytest tests/ -v
Module Directory Structure
resolver/src/pyvcad_attribute_resolver/
├── __init__.py # core public API
├── adapt.py # adapt() entry point
├── conversion_entry.py # ConversionEntry dataclass
├── conversion_graph.py # directed graph
├── registry.py # global register/unregister/list/clear
├── solver.py # BFS pathfinder
└── modules/
├── __init__.py # list_modules() discovery
├── foaming/ # built-in foaming filament data
│ ├── __init__.py
│ └── data.py
└── your_model(s)/ # your new module
├── __init__.py
└── data.py
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyvcad_attribute_resolver-3.0.0-py3-none-any.whl.
File metadata
- Download URL: pyvcad_attribute_resolver-3.0.0-py3-none-any.whl
- Upload date:
- Size: 810.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1e8a5425619121d85c432b54ad82a458a9130c610387b1babbd5b98ff750fe8f
|
|
| MD5 |
94d5387a945c1a10f30d028c358b2e6c
|
|
| BLAKE2b-256 |
c35194b4c07170a9c33b2237a501823ceb442a310d047cd5540fe6f6ba036c97
|