|
| 1 | +"""Test the full circuit simulation with mass tracking + interpolated d80.""" |
| 2 | + |
| 3 | +import asyncio |
| 4 | + |
| 5 | +from crusher_circuit import Conveyor, Crusher, FeedSource, PSD, ProductCollector, Screen |
| 6 | +from plugboard.connector import AsyncioConnector |
| 7 | +from plugboard.process import LocalProcess |
| 8 | +from plugboard.schemas import ConnectorSpec |
| 9 | + |
| 10 | +SIZE_CLASSES = [150.0, 106.0, 75.0, 53.0, 37.5, 26.5, 19.0, 13.2, 9.5, 6.7, 4.75] |
| 11 | +FEED_FRACTIONS = [0.05, 0.10, 0.15, 0.20, 0.18, 0.12, 0.08, 0.05, 0.04, 0.02, 0.01] |
| 12 | + |
| 13 | +connect = lambda src, tgt: AsyncioConnector(spec=ConnectorSpec(source=src, target=tgt)) |
| 14 | + |
| 15 | +process = LocalProcess( |
| 16 | + components=[ |
| 17 | + FeedSource( |
| 18 | + name="feed", |
| 19 | + size_classes=SIZE_CLASSES, |
| 20 | + feed_fractions=FEED_FRACTIONS, |
| 21 | + feed_tonnes=100.0, |
| 22 | + total_steps=50, |
| 23 | + ), |
| 24 | + Crusher( |
| 25 | + name="crusher", |
| 26 | + css=12.0, |
| 27 | + oss=30.0, |
| 28 | + k3=2.3, |
| 29 | + n_stages=2, |
| 30 | + initial_values={"recirc_psd": [None]}, |
| 31 | + ), |
| 32 | + Screen(name="screen", d50c=18.0, alpha=3.5, bypass=0.05), |
| 33 | + Conveyor(name="conveyor", delay_steps=3), |
| 34 | + ProductCollector(name="product", target_d80=20.0), |
| 35 | + ], |
| 36 | + connectors=[ |
| 37 | + connect("feed.feed_psd", "crusher.feed_psd"), |
| 38 | + connect("crusher.product_psd", "screen.crusher_product"), |
| 39 | + connect("screen.undersize", "product.product_psd"), |
| 40 | + connect("screen.oversize", "conveyor.input_psd"), |
| 41 | + connect("conveyor.output_psd", "crusher.recirc_psd"), |
| 42 | + ], |
| 43 | +) |
| 44 | + |
| 45 | + |
| 46 | +async def main() -> None: |
| 47 | + async with process: |
| 48 | + await process.run() |
| 49 | + collector = process.components["product"] |
| 50 | + d80s = [PSD(**h).d80 for h in collector.psd_history] |
| 51 | + masses = [PSD(**h).mass_tonnes for h in collector.psd_history] |
| 52 | + print(f"Steps: {len(d80s)}") |
| 53 | + for i in [0, 1, 2, 3, 4, 5, 6, 7, 9, 14, 19, 29, 49]: |
| 54 | + if i < len(d80s): |
| 55 | + print(f" Step {i + 1:>2}: d80={d80s[i]:.2f} mm, mass={masses[i]:.1f} t") |
| 56 | + unique_d80s = len(set(round(d, 4) for d in d80s)) |
| 57 | + unique_masses = len(set(round(m, 4) for m in masses)) |
| 58 | + print(f"\nUnique d80 values: {unique_d80s}") |
| 59 | + print(f"Unique mass values: {unique_masses}") |
| 60 | + print(f"d80 range: {min(d80s):.2f} - {max(d80s):.2f} mm") |
| 61 | + print(f"Mass range: {min(masses):.1f} - {max(masses):.1f} t") |
| 62 | + ok = unique_d80s > 1 and unique_masses > 1 |
| 63 | + print("PASS" if ok else "FAIL - no dynamics") |
| 64 | + |
| 65 | + |
| 66 | +asyncio.run(main()) |
0 commit comments