Framework
jaxonomy.framework
BlockInitializationError
Bases: JaxonomyError
A generic error to be thrown when a block fails at init time, but the full exceptions are known to cause issues, eg. with ray serialization.
Source code in jaxonomy/framework/error.py
227 228 229 230 231 232 | |
BlockParameterError
Bases: StaticError
Block parameters are missing or have invalid values.
Source code in jaxonomy/framework/error.py
175 176 177 178 | |
BlockRuntimeError
Bases: JaxonomyError
A generic error to be thrown when a block fails at runtime, but the full exceptions are known to cause issues, eg. with ray serialization.
Source code in jaxonomy/framework/error.py
241 242 243 244 245 246 | |
BusUnit
dataclass
Compound unit carrying one :class:Unit per named bus field.
Attached to the output port of a :class:BusCreator (and the
matching input port of a :class:BusSelector) so that the
connect-time consistency check can verify each field's unit
individually.
Attributes:
| Name | Type | Description |
|---|---|---|
fields |
Mapping[str, Unit]
|
Mapping from bus field name to its :class: |
Source code in jaxonomy/framework/units.py
940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 | |
field_unit(name)
Return the :class:Unit for name, or None if absent.
Used by :class:BusSelector to look up its output-port unit
when wired downstream of a unit-tagged bus.
Source code in jaxonomy/framework/units.py
987 988 989 990 991 992 993 | |
ContextBase
dataclass
Context object containing state, parameters, etc for a system.
NOTE: Type hints in ContextBase indicate the union between what would be returned by a LeafContext and a DiagramContext. See type hints of the subclasses for the specific argument and return types.
Attributes:
| Name | Type | Description |
|---|---|---|
owning_system |
SystemBase
|
The owning system of the context. |
time |
Scalar
|
The time associated with the context. Will be None unless the context is the root context. |
is_initialized |
bool
|
Flag indicating if the context is initialized. This should only be set by the ContextFactory during creation. |
Source code in jaxonomy/framework/context.py
131 132 133 134 135 136 137 138 139 140 141 142 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 170 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 202 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 237 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 274 275 276 277 278 | |
__getitem__(key)
abstractmethod
Get the subcontext associated with the given system ID.
For leaf contexts, this will return self, but the method is provided
so that there is a consistent interface for working with either an
individual LeafSystem or tree-structured Diagram.
For nested diagrams, intermediate diagrams do not have associated contexts, so indexing will fail.
Source code in jaxonomy/framework/context.py
156 157 158 159 160 161 162 163 164 165 166 167 | |
with_continuous_state(value)
abstractmethod
Create a copy of this context, replacing the continuous state.
Source code in jaxonomy/framework/context.py
202 203 204 205 | |
with_discrete_state(value)
abstractmethod
Create a copy of this context, replacing the discrete state.
Source code in jaxonomy/framework/context.py
222 223 224 225 | |
with_mode(value)
abstractmethod
Create a copy of this context, replacing the mode.
Source code in jaxonomy/framework/context.py
247 248 249 250 | |
with_new_state()
abstractmethod
Create a copy of this context, replacing the state with a new state.
Source code in jaxonomy/framework/context.py
192 193 194 195 | |
with_parameter(name, value)
Create a copy of this context, replacing the specified parameter.
Source code in jaxonomy/framework/context.py
260 261 262 | |
with_parameters(new_parameters)
abstractmethod
Create a copy of this context, replacing only the specified parameters.
Source code in jaxonomy/framework/context.py
264 265 266 267 | |
with_state(state)
abstractmethod
Create a copy of this context, replacing the entire state.
Source code in jaxonomy/framework/context.py
187 188 189 190 | |
with_subcontext(key, ctx)
abstractmethod
Create a copy of this context, replacing the specified subcontext.
Source code in jaxonomy/framework/context.py
169 170 171 172 | |
with_time(value)
Create a copy of this context, replacing time with the given value.
This should only be called on the root context, since it is expected that all subcontexts will have a time value of None to avoid any conflicts.
Source code in jaxonomy/framework/context.py
174 175 176 177 178 179 180 | |
with_updated_parameters()
abstractmethod
Create a copy of this context, updating all parameters to their current values.
Source code in jaxonomy/framework/context.py
255 256 257 258 | |
DependencyTicket
Singleton class for managing unique dependency tickets.
Source code in jaxonomy/framework/dependency_graph.py
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | |
Diagram
dataclass
Bases: SystemBase
Composite block-diagram representation of a dynamical system.
A Diagram is a collection of Systems connected together to form a larger hybrid dynamical system. Diagrams can be nested to any depth, creating a tree-structured block diagram.
NOTE: The Diagram class is not intended to be constructed directly. Instead,
use the DiagramBuilder to construct a Diagram, which will pass the appropriate
information to this constructor.
Source code in jaxonomy/framework/diagram.py
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 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 170 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 202 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 237 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 274 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 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 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 430 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 502 503 504 505 506 507 508 509 510 511 512 513 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 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 | |
continuous_substep_vector
property
T-133: per-leaf multirate substep vectors, in leaf_systems
order (the same ordering mass_matrix relies on for alignment
with the flattened continuous state).
has_dirty_static_parameters
property
Check if any static parameters have been modified.
check_no_algebraic_loops()
Check for algebraic loops in the diagram.
This is a more or less direct port of the Drake method DiagramBuilder::ThrowIfAlgebraicLoopExists. Some comments are verbatim explanations of the algorithm implemented there.
Source code in jaxonomy/framework/diagram.py
908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 | |
check_types(context, error_collector=None)
Perform any system-specific static analysis.
Source code in jaxonomy/framework/diagram.py
358 359 360 361 362 363 364 365 366 367 368 | |
declare_dynamic_parameter(name, parameter)
Declare a parameter for this system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the parameter. |
required |
parameter
|
Parameter
|
The parameter object. |
required |
Source code in jaxonomy/framework/diagram.py
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 | |
eval_subsystem_input_port(context, port_locator)
Evaluate the input port for a child of this system given the root context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
ContextBase
|
root context for this system |
required |
port_locator
|
InputPortLocator
|
tuple of (system, port_index) identifying the input port to evaluate |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Array |
Array
|
Value returned from evaluating the subsystem port. |
Raises:
| Type | Description |
|---|---|
InputNotConnectedError
|
if the input port is not connected |
Source code in jaxonomy/framework/diagram.py
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 502 503 504 505 506 507 508 509 510 511 512 | |
eval_subsystem_output_port(context, port_locator)
"Evaluate the output port for a child of this system given the root context.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
ContextBase
|
root context for this system |
required |
port_locator
|
OutputPortLocator
|
tuple of (system, port_index) identifying the output port to evaluate |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Array |
Array
|
Value returned from evaluating the subsystem port. |
Source code in jaxonomy/framework/diagram.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 | |
export_input(locator, port_name)
Export a subsystem input port as a diagram-level input.
This should typically only be called during construction by DiagramBuilder. The standard workflow will be to call export_input on the builder object, which will automatically call this method on the Diagram once created.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locator
|
InputPortLocator
|
tuple of (system, port_index) identifying the input port to export |
required |
port_name
|
str
|
name of the new exported input port |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
index of the exported input port in the diagram input_ports list |
Source code in jaxonomy/framework/diagram.py
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 | |
export_output(locator, port_name)
Export a subsystem output port as a diagram-level output.
This should typically only be called during construction by DiagramBuilder. The standard workflow will be to call export_input on the builder object, which will automatically call this method on the Diagram once created.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locator
|
OutputPortLocator
|
tuple of (system, port_index) identifying the output port to export |
required |
port_name
|
str
|
name of the new exported output port |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
index of the exported output port in the diagram output_ports list |
Source code in jaxonomy/framework/diagram.py
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 | |
get_parameter(path)
Get a parameter by dot-separated path (child blocks and nested diagrams).
For a path "block.param", block must be a direct child name of
this diagram; the remainder is resolved on that child (recursively for
nested diagrams). A single segment refers to this diagram's own
parameters (same as :meth:SystemBase.get_parameter).
Examples:
diagram.get_parameter("gain.gain") for a child named gain
with parameter gain.
Raises:
| Type | Description |
|---|---|
KeyError
|
If a segment does not match a child or parameter. |
Source code in jaxonomy/framework/diagram.py
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | |
initialize_static_data(context)
Perform any system-specific static analysis.
Source code in jaxonomy/framework/diagram.py
638 639 640 641 642 | |
list_parameters(prefix='')
Flatten parameters under this diagram with dot-notation keys.
Includes this diagram's own parameters (if any), then each child's
parameters prefixed by child_name.. Nested diagrams recurse.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prefix
|
str
|
Internal use: prepend to every key (non-empty when called recursively from a parent diagram). |
''
|
Source code in jaxonomy/framework/diagram.py
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 | |
post_simulation_finalize()
Perform any post-simulation cleanup for this system.
Source code in jaxonomy/framework/diagram.py
302 303 304 305 | |
print_schedule(*, format='text', file=None, ensure_initialized=True)
Print the inferred sample-time schedule of this diagram.
Renders one entry per rate group — period (for discrete blocks), the leaves that fire at that rate, any detected rate mismatches, and the deterministic execution order. Pure inspection helper; does not mutate the diagram or its contexts.
T-105-followup-print-schedule-pre-context: by default,
print_schedule() lazily calls :meth:create_context() first
so that discrete blocks whose periodic events are registered in
their :meth:initialize hook (e.g. :class:PIDDiscrete,
:class:Decimator, :class:UnitDelay, :class:ZeroOrderHold)
are bucketed into the correct rate group. Pre-fix those blocks
showed up as constant when print_schedule() ran before
any context had been created, because the periodic event hadn't
yet been declared. The lazy create_context() call is
idempotent and cheap on already-initialised diagrams; if it
fails (e.g. the diagram has missing connections), the schedule
is rendered anyway with a one-line warning explaining the
rate-group output may be incomplete. Pass
ensure_initialized=False to opt out and use the pre-fix
behaviour (useful for debugging the initialisation path
itself).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
format
|
str
|
|
'text'
|
file
|
Destination file-like object. Defaults to |
None
|
|
ensure_initialized
|
bool
|
If True (default), call
:meth: |
True
|
Examples:
>>> diagram.print_schedule()
rate groups:
discrete(period=0.001, offset=0.0): ctrl_inner
discrete(period=0.01, offset=0.0): ctrl_outer
continuous: plant
execution order: ...
>>> with open("schedule.md", "w") as f:
... diagram.print_schedule(format="markdown", file=f)
See also
:func:jaxonomy.simulation.rate_groups.rate_summary — the
underlying string formatter, useful when you want the
result as a string for embedding in a manifest or PR body.
:func:jaxonomy.simulation.rate_groups.rate_summary_dot — the
DOT-format companion for graphviz visualization.
Source code in jaxonomy/framework/diagram.py
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 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 237 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 | |
with_parameters(updates)
Return a new diagram with parameters replaced (dot-notation paths).
Grouping is by top-level block name; nested paths are forwarded recursively. The original diagram is unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
updates
|
dict[str, Any]
|
Map from dot paths to new values, e.g.
|
required |
Returns:
| Name | Type | Description |
|---|---|---|
New |
Diagram
|
class: |
Raises:
| Type | Description |
|---|---|
KeyError
|
Unknown block or parameter. |
TypeError
|
Attempt to replace a static parameter. |
Source code in jaxonomy/framework/diagram.py
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 | |
DiagramBuilder
Class for constructing block diagram systems.
The DiagramBuilder class is responsible for building a diagram by adding systems, connecting ports,
and exporting inputs and outputs. It keeps track of the registered systems, input and output ports,
and the connection map between input and output ports of the child systems.
Source code in jaxonomy/framework/diagram_builder.py
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 133 134 135 136 137 138 139 140 141 142 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 170 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 202 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 237 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 274 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 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 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 430 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 502 503 504 505 506 507 508 509 510 511 512 513 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 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 | |
__init__(*, validate_rates_at_connect=None, unit_conversion='auto', auto_insert_rate_transitions=False)
Construct a DiagramBuilder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
validate_rates_at_connect
|
str | bool | None
|
T-105 Phase 2 — opt-in connect-time
multirate consistency check. When set to |
None
|
unit_conversion
|
str
|
T-104 followup — controls behaviour when two
connected ports share base-dimensions but differ only by a
scalar |
'auto'
|
auto_insert_rate_transitions
|
bool
|
T-105-followup-phase3 — when
|
False
|
Source code in jaxonomy/framework/diagram_builder.py
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 133 134 135 136 137 138 139 140 141 142 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 170 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 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | |
add(*systems)
add(system: SystemBase) -> SystemBase
add(system: SystemBase, *systems: SystemBase) -> List[SystemBase]
Add one or more systems to the diagram.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
*systems SystemBase
|
System(s) to add to the diagram. |
required |
Returns:
| Type | Description |
|---|---|
List[SystemBase] | SystemBase
|
List[SystemBase] | SystemBase: The added system(s). Will return a single system if there is only a single system in the argument list. |
Raises:
| Type | Description |
|---|---|
BuilderError
|
If the diagram has already been built. |
BuilderError
|
If the system is already registered. |
BuilderError
|
If the system name is not unique. |
Source code in jaxonomy/framework/diagram_builder.py
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | |
build(name='root', ui_id=None, parameters=None)
Builds a Diagram system with the specified name and system ID.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the diagram. Defaults to "root". |
'root'
|
ui_id
|
str
|
The unique identifier for the diagram. |
None
|
parameters
|
dict[str, Parameter]
|
A dictionary of dynamic parameters to declare for the diagram. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
Diagram |
Diagram
|
The newly constructed diagram. |
Raises:
| Type | Description |
|---|---|
EmptyDiagramError
|
If no systems are registered in the diagram. |
BuilderError
|
If the diagram has already been built. |
AlgebraicLoopError
|
If an algebraic loop is detected in the diagram. |
DisconnectedInputError
|
If an input port is not connected. |
Source code in jaxonomy/framework/diagram_builder.py
683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 | |
connect(src, dest)
Connect an output port to an input port.
The input port and output port must both belong to systems that have already been added to the diagram. The input port must not already be connected to another output port.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
src
|
OutputPort
|
The output port to connect. |
required |
dest
|
InputPort
|
The input port to connect. |
required |
Raises:
| Type | Description |
|---|---|
BuilderError
|
If the diagram has already been built. |
BuilderError
|
If the source system is not registered. |
BuilderError
|
If the destination system is not registered. |
BuilderError
|
If the input port is already connected. |
BuilderError
|
If src is an InputPort or dest is an OutputPort. |
Source code in jaxonomy/framework/diagram_builder.py
259 260 261 262 263 264 265 266 267 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 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 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 | |
export_input(port, name=None)
Export an input port of a child system as a diagram-level input.
The input port must belong to a system that has already been added to the diagram. The input port must not already be connected to another output port.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
port
|
InputPort
|
The input port to export. |
required |
name
|
str
|
The name to assign to the exported input port. If not provided, a unique name will be generated. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The index (in the to-be-built diagram) of the exported input port. |
Raises:
| Type | Description |
|---|---|
BuilderError
|
If the diagram has already been built. |
BuilderError
|
If the system is not registered. |
BuilderError
|
If the input port is already connected. |
BuilderError
|
If the input port name is not unique. |
Source code in jaxonomy/framework/diagram_builder.py
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 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 | |
export_output(port, name=None)
Export an output port of a child system as a diagram-level output.
The output port must belong to a system that has already been added to the diagram.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
port
|
OutputPort
|
The output port to export. |
required |
name
|
str
|
The name to assign to the exported output port. If not provided, a unique name will be generated. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The index (in the to-be-built diagram) of the exported output port. |
Raises:
| Type | Description |
|---|---|
BuilderError
|
If the diagram has already been built. |
BuilderError
|
If the system is not registered. |
BuilderError
|
If the output port name is not unique. |
Source code in jaxonomy/framework/diagram_builder.py
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 | |
DiagramContext
dataclass
Bases: ContextBase
Source code in jaxonomy/framework/context.py
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 430 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 502 503 504 505 506 507 508 509 510 511 512 513 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 | |
with_parameters(new_parameters)
Create a copy of this context, replacing only the specified parameters.
Source code in jaxonomy/framework/context.py
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 | |
DiscreteUpdateEvent
dataclass
Bases: Event
Event representing a discrete update in a hybrid system.
Source code in jaxonomy/framework/event.py
362 363 364 365 366 367 368 369 370 371 372 373 | |
DtypeMismatchError
Bases: StaticError
Block parameters or input/outputs have mismatched dtypes.
Source code in jaxonomy/framework/error.py
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | |
EnabledMode
Allowed string values for EnabledSubsystem.mode.
Source code in jaxonomy/framework/containers.py
103 104 105 106 107 108 109 110 111 112 | |
EnabledStateMode
Allowed string values for EnabledSubsystem.state_mode.
Controls how the continuous state (declared via state_dynamics)
evolves while the enable signal is false:
HOLD(default): freeze the state at its current value (xdot = 0while disabled). Resumes integration on re-enable.RESET: snap the state back toinitial_stateon every disable→enable transition (so each enable window starts from the configured initial value). While disabled, the state is held.FREE: the state evolves according tostate_dynamicsregardless of enable. Only the output is masked permode=.
Source code in jaxonomy/framework/containers.py
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
EnabledSubsystem
Bases: LeafSystem
Container block: run a submodel only while an enable signal is true.
This is the subsystem-framing wrapper around the existing
:class:jaxonomy.library.Conditional primitive (T-009). It exists
as a separate class so that:
- The block-diagram-vocabulary name
EnabledSubsystemis discoverable next to the rest of the container family. - We can later extend the
mode="hold"path with subsystem-state semantics (per-block discrete-state binding) without disturbing the lighterConditionalprimitive.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
submodel
|
Callable
|
Callable |
required |
n_inputs
|
int
|
Number of submodel inputs (does NOT include the enable port). Input port 0 is always the enable signal; ports 1..n_inputs carry the submodel inputs. |
1
|
mode
|
Literal['reset', 'passthrough', 'hold']
|
One of
|
RESET
|
initial_value
|
Output value when disabled in reset mode, and the seed for the held discrete state in hold mode. Used to infer output shape/dtype. |
0.0
|
|
hold_period
|
float | None
|
Sample period (seconds) for the held snapshot in
hold mode. Required iff |
None
|
state_mode
|
Literal['hold', 'reset', 'free']
|
One of |
HOLD
|
state_dynamics
|
Callable | None
|
Optional callable
|
None
|
initial_state
|
Initial value of the continuous state. Required
when |
None
|
|
name
|
Optional block name. |
required |
Source code in jaxonomy/framework/containers.py
156 157 158 159 160 161 162 163 164 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 194 195 196 197 198 199 200 201 202 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 237 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 274 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 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 | |
ErrorCollector
Tool used to collect errors related to users model specification. Errors related to user model specification are identified during model static analysis, e.g. context creation, type checking, etc.
An instance of this tool can be created, and then passed down a tree of function calls to collect errors found any where in the tree. Locally in the tree it can be determined whether it is ok to continue or not. This tool enables collecting errors up until the point when continuation is no longer possible.
Note: this latter behavior, where sometimes there is early exit desired, and all other "pipeline" operations are "nullified", might better be implemented using pymonad:Either class.
Source code in jaxonomy/framework/error.py
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 | |
add_error(error)
Add an error to the collection.
Source code in jaxonomy/framework/error.py
327 328 329 330 331 332 333 334 335 | |
context(parent=None)
classmethod
A context manager convenience to use when tracing errors.
Use as:
with ErrorCollector.trace(error_context) as ec:
...
If the parent context is None, then exceptions will pass through without being collected. Else, exceptions will be collected in the parent context.
Source code in jaxonomy/framework/error.py
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | |
EventCollection
A collection of events owned by a system.
Users should not need to interact with these objects directly. They are intended to be used internally by the simulation framework for handling events in hybrid system simulation.
These contain callback functions that update the context in various ways when the event is triggered. There will be different "collections" for each trigger type in simulation (e.g. periodic vs zero-crossing). Within the collections, events are broken out by function (e.g. discrete vs unrestricted updates).
There are separate implementations for leaf and diagram systems, where the DiagramCEventCollection preserves the tree structure of the underlying Diagram. However, the interface in both cases is the same and is identical to the interface defined by EventCollection.
Source code in jaxonomy/framework/event.py
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 | |
ForLoop
Bases: LeafSystem
Container block: run body_fn n_iter times per major step.
ForLoop wraps :func:jax.lax.fori_loop. The block declares a
single input port carrying the initial carry value and a single
output port returning the carry after n_iter iterations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body_fn
|
Callable
|
Callable |
required |
n_iter
|
int
|
Number of iterations. Must be a non-negative Python int
(static); a runtime-traced |
required |
name
|
Optional block name. |
required |
Differentiability
:func:jax.grad flows through body_fn's parameters and
through the initial carry. The loop count n_iter is static
and not differentiable.
Example
A body that accumulates i into the carry over 10
iterations yields carry_initial + (0+1+...+9) = carry + 45.
Notes
body_fnmust close over any constants it needs; thei-th iteration receives only(i, carry).- Per T-005, default float dtype is float64 unless the active
precision policy says otherwise;
ForLoopdoes not cast.
Source code in jaxonomy/framework/containers.py
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 682 683 684 685 686 687 688 689 690 691 692 693 694 | |
IntegerTime
Class for managing conversion between decimal and integer time.
Source code in jaxonomy/framework/event.py
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
as_decimal(time)
classmethod
Convert an integer time to a floating-point time.
Source code in jaxonomy/framework/event.py
157 158 159 160 | |
from_decimal(time)
classmethod
Convert a floating-point time to an integer time.
Source code in jaxonomy/framework/event.py
150 151 152 153 154 155 | |
JaxonomyError
Bases: Exception
Base class for all custom jaxonomy errors.
Source code in jaxonomy/framework/error.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
__init__(message=None, *, system=None, system_id=None, name_path=None, ui_id_path=None, port_index=None, port_name=None, port_direction=None, parameter_name=None, loop=None)
Create a new JaxonomyError.
Only message is a positional argument, all others are keyword arguments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
A custom error message, defaults to the error class name. |
None
|
|
system
|
SystemBase
|
The system that the error occurred in, if available. |
None
|
system_id
|
Hashable
|
The id of the system that the error occurred in, use if system can't be passed. |
None
|
name_path
|
list[str]
|
The name path of the block that the error occurred in, use if system can't be passed. |
None
|
ui_id_path
|
list[str]
|
The ui_id (uuid) path of the block that the error occurred in, use if system can't be passed. |
None
|
port_index
|
int
|
The index of the port that the error occurred at. |
None
|
port_name
|
str
|
The name of the port that the error occurred at. |
None
|
port_direction
|
str
|
The direction of the port that the error occurred at. |
None
|
parameter_name
|
str
|
The name of the parameter that the error occurred at. |
None
|
loop
|
list[DirectedPortLocator]
|
A list of I/O ports where the error occurred (eg. AlgebraicLoopError). |
None
|
Source code in jaxonomy/framework/error.py
29 30 31 32 33 34 35 36 37 38 39 40 41 42 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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
caused_by(exc_type)
Check if this error is or was caused by another error type.
For instance, if a JaxonomyError is raised because of a TypeError, this method will return True when called with TypeError as exc_type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
exc_type
|
type
|
The type of exception to check for (eg. TypeError) |
required |
Returns:
| Name | Type | Description |
|---|---|---|
bool |
True if the error is or was caused by the given exception type. |
Source code in jaxonomy/framework/error.py
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
LeafContext
dataclass
Bases: ContextBase
Source code in jaxonomy/framework/context.py
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 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 | |
__getitem__(key)
Dummy indexing for compatibility with DiagramContexts, returning self.
Source code in jaxonomy/framework/context.py
289 290 291 292 293 | |
with_parameters(new_parameters)
Create a copy of this context, replacing only the specified parameters.
Source code in jaxonomy/framework/context.py
379 380 381 382 383 384 385 386 387 | |
with_subcontext(key, ctx)
Dummy replacement for compatibility with DiagramContexts, returning ctx.
Source code in jaxonomy/framework/context.py
295 296 297 298 299 300 301 302 303 | |
LeafState
dataclass
Container for state information for a leaf system.
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Name of the leaf system that owns this state. |
continuous_state |
LeafStateComponent
|
Continuous state of the system, i.e. the component of state that evolves in continuous time. If the system has no continuous state, this will be None. |
discrete_state |
LeafStateComponent
|
Discrete state of the system, i.e. one or more components of state that do not change continuously with ime (not necessarily discrete-valued). If the system has no discrete state, this will be None. |
mode |
int
|
An integer value indicating the current "mode", "stage", or discrete-valued state component of the system. Used for finite state machines or multi-stage hybrid systems. If the system has no mode, this will be None. |
cache |
tuple[LeafStateComponent]
|
The current values of sample-and-hold outputs from the system. In a pure discrete system these would not be state components (just results of feedthrough computations), but in a hybrid or multirate system they act as discrete state from the perspective of continuous or asynchronous discrete components of the system. Hence, they are stored in the state, but are maintained separately from the normal internal state of the system. |
Notes
(1) This class is immutable. To modify a LeafState, use the with_* methods.
(2) The type annotations for state components are LeafStateComponent, which is a union of array, tuple, and named tuple. The most common case is arrays, but this allows for more flexibility in defining state components, e.g. a second-order system can define a named tuple of generalized coordinates and velocities rather than concatenating into a single array.
Source code in jaxonomy/framework/state.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 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 133 134 135 136 137 138 139 140 141 142 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 | |
with_cached_value(index, value)
Create a copy of this LeafState with the specified cache value replaced.
Source code in jaxonomy/framework/state.py
158 159 160 161 162 | |
with_continuous_state(value)
Create a copy of this LeafState with the continuous state replaced.
Source code in jaxonomy/framework/state.py
104 105 106 107 108 109 | |
with_discrete_state(value)
Create a copy of this LeafState with the discrete state replaced.
Source code in jaxonomy/framework/state.py
135 136 137 138 139 140 | |
with_mode(value)
Create a copy of this LeafState with the mode replaced.
Source code in jaxonomy/framework/state.py
150 151 152 | |
LeafSystem
dataclass
Bases: SystemBase
Basic building block for dynamical systems.
A LeafSystem is a minimal component of a system model in jaxonomy, containing no
subsystems. Inputs, outputs, state, parameters, updates, etc. can be added to the
block using the various declare_* methods. The built-in blocks in
jaxonomy.library are all subclasses of LeafSystem, as are any custom blocks defined
by the user.
Source code in jaxonomy/framework/leaf_system.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 237 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 274 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 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 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 430 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 502 503 504 505 506 507 508 509 510 511 512 513 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 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 | |
continuous_state_default
property
The declared default continuous-state value (read-only).
This is the default_value passed to declare_continuous_state
(or the array inferred from shape / dtype), i.e. the value
that seeds context.continuous_state before any user override.
Returns None when the block has no continuous state. Exposed as a
documented accessor so callers don't have to reach into the private
_default_continuous_state attribute (T-C2-followup).
continuous_substep_vector
property
T-133: per-entry multirate substep factors for this block.
Returns pytree-structured int vectors aligned with the flattened
continuous state (same leaves-concatenation ordering the ODE
solvers use for mass_matrix), or None when the block has
no continuous state. Every entry carries the block-level factor
declared via declare_continuous_state(substeps=N) (default 1).
has_multirate_substeps
property
True when this block declared substeps > 1 (T-133).
configure_continuous_state(callback_idx, shape=None, default_value=None, dtype=None, ode=None, mass_matrix=None, as_array=True, requires_inputs=True, prerequisites_of_calc=None)
Configure a continuous state component for the system.
The ode callback computes the time derivative of the continuous state based on the
current time, state, and any additional inputs. If ode is not provided, a default
zero vector of the same size as the continuous state is used. If provided, the ode
callback should have the signature ode(time, state, *inputs, **params) -> xcdot.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback_idx
|
int
|
The index of the callback in the system's callback list. |
required |
shape
|
ShapeLike
|
The shape of the continuous state vector. Defaults to None. |
None
|
default_value
|
Array
|
The initial value of the continuous state vector. Defaults to None. |
None
|
dtype
|
DTypeLike
|
The data type of the continuous state vector. Defaults to None. |
None
|
ode
|
Callable
|
The callback for computing the time derivative of the continuous state.
Should have the signature:
|
None
|
mass_matrix
|
Array
|
The mass matrix for the continuous state. Defaults to None. If provided, must be a square matrix with the same shape as the continuous state. Using a mass matrix different from the identity in any LeafSystem will require the use of a compatible continuous-time solver (currently only BDF is supported). Currently mass matrices are also only supported for scalar- or vector-valued continuous states ( i.e. no matrices or other PyTree-structured states). |
None
|
as_array
|
bool
|
If True, treat the default_value as an array-like (cast if necessary). Otherwise, it will be stored as the default state without modification. |
True
|
requires_inputs
|
bool
|
If True, indicates that the ODE computation requires inputs. |
True
|
prerequisites_of_calc
|
List[DependencyTicket]
|
The dependency tickets for the ODE computation. Defaults to None, in
which case the assumption is a dependency on either (time, continuous
state) if |
None
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If neither shape nor default_value is provided, or if the mass matrix is inconsistent with the continuous state. |
Notes
(1) Only one of shape and default_value should be provided. If default_value
is provided, it will be used as the initial value of the continuous state. If
shape is provided, the initial value will be a zero vector of the given shape
and specified dtype.
Source code in jaxonomy/framework/leaf_system.py
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 | |
configure_output_port(port_index, callback, period=None, offset=0.0, prerequisites_of_calc=None, default_value=None, requires_inputs=None)
Configure an output port in the LeafSystem.
See declare_output_port for a description of the arguments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
port_index
|
int
|
The index of the output port to configure. |
required |
Returns:
| Type | Description |
|---|---|
|
None |
Source code in jaxonomy/framework/leaf_system.py
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 | |
configure_periodic_update(event_index, callback, period, offset, enable_tracing=None)
Configure an existing periodic update event.
The event will be triggered at regular intervals defined by the period and
offset parameters. The callback should have the signature
callback(time, state, *inputs, **params) -> xd_plus, where xd_plus is the
updated value of the discrete state.
This callback should be written to compute the "plus" value of the discrete state component given the "minus" values of all state components and inputs.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_index
|
int
|
The index of the event to configure. |
required |
callback
|
Callable
|
The callback function defining the update. |
required |
period
|
Scalar
|
The period at which the update event occurs. |
required |
offset
|
Scalar
|
The offset at which the first occurrence of the event is triggered. |
required |
enable_tracing
|
bool
|
If True, enable tracing for this event. Defaults to None. |
None
|
Source code in jaxonomy/framework/leaf_system.py
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 | |
declare_cache(callback, period=None, offset=0.0, name=None, prerequisites_of_calc=None, default_value=None, requires_inputs=True)
Declare a stored computation for the system.
This method accepts a callback function with the block-level signature
callback(time, state, *inputs, **parameters) -> value
and wraps it to have the signature
callback(context) -> value
This callback can optionally be used to define a periodic update event that refreshes the cached value. Other calculations (e.g. sample-and-hold output ports) can then depend on the cached value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
Callable
|
The callback function defining the cached computation. |
required |
period
|
float
|
If not None, the callback function will be used to define a periodic update event that refreshes the value. Defaults to None. |
None
|
offset
|
float
|
The offset of the periodic update event. Defaults to 0.0. Will be ignored
unless |
0.0
|
name
|
str
|
The name of the cached value. Defaults to None. |
None
|
default_value
|
Array
|
The default value of the result, if known. Defaults to None. |
None
|
requires_inputs
|
bool
|
If True, the callback will eval input ports to gather input values. This will add a bit to compile time, so setting to False where possible is recommended. Defaults to True. |
True
|
prerequisites_of_calc
|
List[DependencyTicket]
|
The dependency tickets for the computation. Defaults to None, in which
case the default is to assume dependency on either (inputs) if
|
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The index of the callback in |
Source code in jaxonomy/framework/leaf_system.py
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 | |
declare_continuous_state(shape=None, default_value=None, dtype=None, ode=None, mass_matrix=None, as_array=True, requires_inputs=True, prerequisites_of_calc=None, substeps=1, project=None)
Declare a continuous state component for the system.
The continuous state value is read inside callbacks as
state.continuous_state (the state argument of the ode /
output callbacks). Unpack contract (T-C3-followup): the shape of
state.continuous_state mirrors exactly what you passed as
default_value (or the zeros array implied by shape /
dtype):
- A scalar default (
jnp.array(0.0)) gives a scalarstate.continuous_state— read it directly, do not index. - A vector default (
jnp.zeros(3)) gives a length-3 array — index / unpack asx, y, z = state.continuous_stateorstate.continuous_state[i]. - A PyTree default (tuple / NamedTuple / dict) gives back the same
PyTree structure; your
odemust returnxcdotwith the identical structure.
The ode callback's return value must match the
default_value structure element-for-element, since it is added to
the state during integration. A common error is declaring a scalar
state but returning jnp.array([xdot]) (shape (1,)) from the
ode — keep both scalar or both vector.
Multirate substepping (T-133): substeps=N declares that this
block's continuous dynamics have a fast time constant needing N
inner integration steps per outer solver step (e.g. a motor's
electrical winding inside a 1 kHz control loop). Honored by the
fixed-step rk4 solver (SimulatorOptions(ode_solver_method=
"rk4")): the block's states advance with N RK4 substeps of
h/N while the rest of the diagram takes one step of h,
with first-order (zero-order-hold) coupling at the boundary —
each side sees the other's start-of-step values, matching the
semantics of a hand-rolled JIT-safe substep loop. Adaptive solvers
(dopri5/bdf) ignore the declaration — they control
stiffness through global step adaptation. N must be a static
Python int >= 1; the default 1 is byte-equivalent to the
pre-T-133 behavior.
Reverse-mode autodiff (enable_autodiff=True) is supported —
the substep loop has a static trip count and the checkpointed
adjoint substeps the costates alongside their primals. Gradient
accuracy carries the scheme's first-order coupling error: the
adjoint converges to the true sensitivity linearly in the outer
step h (exact FD agreement is only recovered as h is
refined), and for dynamics unstable at the outer step the
adjoint's reverse-time primal re-integration further limits
accuracy. Reduce the outer step when gradients through the
coupling interface need to be tight.
Declared state projection (T-132): project=fn declares that
this block's continuous state lives on a manifold and supplies
the retraction back onto it — e.g. unit-quaternion
renormalization for an attitude state (nq=4 integrated
componentwise drifts off the unit sphere under any one-step
integrator). fn(x) -> x receives the state in its declared
structure, must be shape-preserving and jit-safe, and is applied
by the simulator at the end of every major step (composing
with, and independent of, the T-003a DAE projection). Within-step
drift is bounded by the step size; the recorded trajectory and
all values other blocks see at major-step boundaries are on the
manifold. Differentiable: the projection participates in
reverse-mode AD as ordinary traced ops.
Source code in jaxonomy/framework/leaf_system.py
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 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 | |
declare_continuous_state_output(name=None)
Declare a continuous state output port in the system.
This method creates a new block-level output port which returns the full continuous state of the system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the output port. Defaults to None (autogenerate name). |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The index of the new output port. |
Source code in jaxonomy/framework/leaf_system.py
1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 | |
declare_discrete_state(shape=None, default_value=None, dtype=None, as_array=True, name=None)
Declare a discrete state component for the system.
The discrete state is a component of the system's state that can be updated at specific events, such as zero-crossings or periodic updates.
.. note::
Currently only one discrete state component is supported per
LeafSystem. If declare_discrete_state is called more than once,
the second call will silently overwrite the first. To store several
independent values, pack them into a single array and split inside your
update callback.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
shape
|
ShapeLike
|
The shape of the discrete state. Defaults to None. |
None
|
default_value
|
Array
|
The initial value of the discrete state. Defaults to None. |
None
|
dtype
|
DTypeLike
|
The data type of the discrete state. Defaults to None. |
None
|
as_array
|
bool
|
If True, treat the default_value as an array-like (cast if necessary). Otherwise, it will be stored as the default state without modification. |
True
|
name
|
str
|
Readability label for the discrete state (parity with
|
None
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If as_array is True and neither shape nor default_value is provided. |
Notes
(1) Only one of shape and default_value should be provided. If
default_value is provided, it will be used as the initial value of the
continuous state. If shape is provided, the initial value will be a
zero vector of the given shape and specified dtype.
(2) Use declare_periodic_update to declare an update event that
modifies the discrete state at a recurring interval.
Source code in jaxonomy/framework/leaf_system.py
957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 | |
declare_mode_output(name=None)
Declare a mode output port in the system.
This method creates a new block-level output port which returns the component of the system's state corresponding to the discrete "mode" or "stage".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the output port. Defaults to None. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The index of the declared mode output port. |
Source code in jaxonomy/framework/leaf_system.py
1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 | |
declare_output_port(callback=None, period=None, offset=0.0, name=None, prerequisites_of_calc=None, default_value=None, requires_inputs=None, units=None)
Declare an output port in the LeafSystem.
This method accepts a callback function with the block-level signature
callback(time, state, *inputs, **parameters) -> value
and wraps it to the signature expected by SystemBase.declare_output_port:
callback(context) -> value
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
Callable
|
The callback function defining the output port. |
None
|
period
|
float
|
If not None, the port will act as a "sample-and-hold", with the callback function used to define a periodic update event that refreshes the value that will be returned by the port. Typically this should match the update period of some associated update event in the system. Defaults to None. |
None
|
offset
|
float
|
The offset of the periodic update event. Defaults to 0.0. Will be ignored
unless |
0.0
|
name
|
str
|
The name of the output port. Defaults to None. |
None
|
default_value
|
Array
|
The default value of the output port, if known. Defaults to None. |
None
|
requires_inputs
|
bool | list[int] | None
|
Whether the callback reads input port values. Defaults to Set this to Can also be specified as a list of integer port indices to declare
selective feedthrough (only the listed inputs feed through to this
output). Defaults to |
None
|
prerequisites_of_calc
|
List[DependencyTicket]
|
The dependency tickets for the output port computation. Defaults to
None, in which case the assumption is a dependency on either (nothing)
if |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The index of the declared output port. |
Source code in jaxonomy/framework/leaf_system.py
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 | |
declare_zero_crossing(guard, reset_map=None, start_mode=None, end_mode=None, direction='crosses_zero', terminal=False, name=None, enable_tracing=None, zeno_tolerance=None, grad_guard=None)
Declare an event triggered by a zero-crossing of a guard function.
Optionally, the system can also transition between discrete modes
If start_mode and end_mode are specified, the system will transition
from start_mode to end_mode when the event is triggered according to guard.
This event will be active conditionally on state.mode == start_mode and when
triggered will result in applying the reset map. In addition, the mode will be
updated to end_mode.
If start_mode and end_mode are not specified, the event will always be active
and will not result in a mode transition.
The guard function should have the signature
guard(time, state, *inputs, **parameters) -> float
and the reset map should have the signature of an unrestricted update
reset_map(time, state, *inputs, **parameters) -> state
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
guard
|
Callable
|
The guard function which triggers updates on zero crossing. |
required |
reset_map
|
Callable
|
The reset map which is applied when the event is triggered. If None (default), no reset is applied. |
None
|
start_mode
|
int
|
The mode or stage of the system in which the guard will be actively monitored. If None (default), the event will always be active. |
None
|
end_mode
|
int
|
The mode or stage of the system to which the system will transition when the event is triggered. If start_mode is None, this is ignored. Otherwise it must be specified, though it can be the same as start_mode. |
None
|
direction
|
str
|
The direction of the zero crossing. Options are "crosses_zero" (default), "positive_then_non_positive", "negative_then_non_negative", and "edge_detection". All except edge detection operate on continuous signals; edge detection operates on boolean signals and looks for a jump from False to True or vice versa. |
'crosses_zero'
|
terminal
|
bool
|
If True, the event will halt simulation if and when the zero-crossing occurs. If this event is triggered the reset map will still be applied as usual prior to termination. Defaults to False. |
False
|
name
|
str
|
The name of the event. Defaults to None. |
None
|
enable_tracing
|
bool
|
If True, enable tracing for this event. Defaults to None. |
None
|
Notes
By default the system state does not have a "mode" component, so in
order to declare "state transitions" with non-null start and end modes,
the user must first call declare_default_mode to set the default mode
to be some integer (initial condition for the system).
Source code in jaxonomy/framework/leaf_system.py
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 | |
initialize(**parameters)
Hook for initializing a system. Called during context creation.
If the parameters are instances of Parameter, they will be resolved. If implemented, the function signature should contain all the declared parameters.
This function should not be called directly. It will be called implicitly after init with the resolved parameters.
Source code in jaxonomy/framework/leaf_system.py
299 300 301 302 303 304 305 306 307 308 309 | |
reset_default_values(**dynamic_parameters)
This function is used to reset default values for
continuous/discrete states, ports and mode based on dynamic parameters.
It is called in create_state() and used to reset states in ensemble sims
and optimization with the context method with_new_state().
Note that dtypes and shapes can't be changed after initialization because the diagram may already have been jax-compiled. Only values may change.
Source code in jaxonomy/framework/leaf_system.py
1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 | |
with_parameter(name, value)
Return a copy of this system with one dynamic parameter replaced.
The returned system is a new instance. The original is unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Parameter name (must exist as a dynamic parameter). |
required |
value
|
New value (typically a JAX array for |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
TypeError
|
If |
Source code in jaxonomy/framework/leaf_system.py
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 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 | |
wrap_callback(callback, collect_inputs=True)
Wrap an update function to unpack local variables and block inputs.
The callback should have the signature
callback(time, state, *inputs, **params) -> result
and will be wrapped to have the signature callback(context) -> result,
as expected by the event handling logic.
This is used internally for declaration methods like
declare_periodic_update so that users can write more intuitive
block-level update functions without worrying about the "context", and have
them automatically wrapped to have the right interface. It can also be
called directly by users to wrap their own update functions, for example to
create a callback function for declare_output_port.
The context and state are strictly immutable, so the callback should not attempt to change any values in the context or state. Even in cases where it is impossible to enforce this (e.g. a state component is a list, which is always mutable in Python), the callback should be careful to avoid direct modification of the context or state, which may lead to unexpected behavior or JAX tracer errors.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
Callable
|
The (pure) function to be wrapped. See above for expected signature. |
required |
collect_inputs
|
bool
|
If True, the callback will eval input ports to gather input values. Normally this should be True, but it can be set to False if the return value depends only on the state but not inputs, for instance. This helps reduce the number of expressions that need to be JIT compiled. Can also be specified as a list of integer port indices. Default is True (collect all inputs). |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
Callable |
Callable
|
The wrapped function, with signature |
Source code in jaxonomy/framework/leaf_system.py
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 | |
Parameter
dataclass
Source code in jaxonomy/framework/parameter.py
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 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 | |
__deepcopy__(memo)
Copy fields and re-run post-init so :class:ParameterCache bookkeeping matches.
Source code in jaxonomy/framework/parameter.py
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 | |
unwrap(value)
classmethod
Get the underlying value of raw arrays and Parameter objects alike.
Source code in jaxonomy/framework/parameter.py
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 | |
value_as_api_param(allow_param_name=True, allow_string_literal=True)
Returns an API-compatible expression[1] that defines this parameter
What we return depends on the caller's context, since it depends on whether we are serializing for a model, submodel or block parameter.
The boolean is the value of 'is_string' (means "string literal" or "do not call eval").
[1] The returned string can be serialized to JSON, but it is not an already escaped JSON string!
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
allow_param_name
|
Set to false for (sub)model parameters. Optional. If true, and the value is defined by a name, just the name will be returned. |
True
|
|
allow_string_literal
|
Set to false for (sub)model parameters. Optional. If true, and the value is a string, then the string will be returned and 'is_string' will be returned as True. |
True
|
Source code in jaxonomy/framework/parameter.py
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 | |
ParameterCache
Global parameter value cache used by all :class:Parameter instances.
Thread safety
All public methods are protected by a class-level reentrant lock
(threading.RLock). Using an RLock rather than a plain Lock
is necessary because __compute__ may call param.get() recursively
(for compound parameter expressions), which would deadlock under a
non-reentrant lock held by the outer get() call.
Concurrent simulations in separate threads sharing the same Parameter
objects are serialised correctly. However, mutating a parameter from one
thread while another thread is actively simulating with it is not
recommended — the lock ensures the state remains consistent, but the
simulation semantics of mid-run mutation are undefined.
Source code in jaxonomy/framework/parameter.py
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 430 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 502 503 504 505 506 507 508 509 510 511 512 513 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 | |
print_dependents(param, indent=0)
classmethod
Prints the dependents tree of a parameter
Source code in jaxonomy/framework/parameter.py
477 478 479 480 481 482 483 484 485 | |
RuntimeVariantSubsystem
Bases: LeafSystem
Switch between pre-built submodel choices via a discrete selector input.
This is the runtime counterpart to select_variant / Variant. Unlike
the build-time selector (which never instantiates the unselected branches),
RuntimeVariantSubsystem builds every choice and routes the selected
branch's output through. The selector is a normal input port, so it can be
driven by any discrete control signal in the diagram and the active branch
follows at simulate time. This is the runtime-controlled variant pattern,
as opposed to the label-mode build-time variant.
Implementation: the block stacks all branches' outputs along a new leading
axis and picks out the selected slice with integer indexing. This is the
same mechanism used by MultiPortSwitch (T-118), reused here at the
framework level so it does not pull a library dependency.
Contract — "all branches integrated each step"
Because the underlying stack traces every branch, every choice's
submodel runs on every step and sees the same input trajectory. The
consequences:
-
Pure (memoryless) branches behave exactly as you'd expect: only the selected branch's output is exposed; gradients w.r.t. the active branch's parameters are non-zero, and gradients w.r.t. the others are zero (matching
MultiPortSwitch's data-input semantics). -
The selector is non-differentiable (
round+clipzero out its gradient), as expected for a control signal. -
If a branch holds internal discrete state (e.g. a hold latch) the caller is responsible for supplying that state.
RuntimeVariantSubsystemitself is stateless; if you need stateful sub-Diagrams, hoist the state out, or build the runtime switch by composingMultiPortSwitch(T-118) with N pre-built sub-diagrams in a parentDiagramBuilder.
All branches must return outputs that are broadcast-compatible (the stack op requires a common shape/dtype after broadcasting).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
choices
|
Either a sequence of submodel callables |
required | |
n_inputs
|
int
|
Number of user inputs forwarded to every branch. Input port 0
is always the selector; ports |
1
|
default_choice
|
int
|
Index of the choice used as the default. Stored for introspection / documentation; the runtime selector value still controls which branch is exposed each step. Defaults to 0. |
0
|
name
|
Optional block name. |
required |
Input ports
(0) selector — scalar integer-valued signal in [0, N-1].
Floating values are rounded and clipped.
(1..n_inputs) user inputs forwarded to every branch.
Output ports
(0) The selected branch's output.
Raises:
| Type | Description |
|---|---|
VariantError
|
If |
Source code in jaxonomy/framework/variants.py
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 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 | |
default_choice
property
Default choice index (documentary; runtime selector still rules).
n_choices
property
Number of variant choices held by this block.
ShapeMismatchError
Bases: StaticError
Block parameters or input/outputs have mismatched shapes.
Source code in jaxonomy/framework/error.py
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | |
StaticError
Bases: JaxonomyError
Wraps a Python exception to record the offending block id. The original exception is found in the 'cause' field.
See jaxonomy.framework.context_factory._check_types for use.
This is called 'static' (as opposed to say 'runtime') meaning this is for wrapping errors detected prior to running a simulation.
Source code in jaxonomy/framework/error.py
163 164 165 166 167 168 169 170 171 172 | |
SystemBase
dataclass
Basic building block for simulation in jaxonomy.
NOTE: Type hints in SystemBase indicate the union between what would be returned by a LeafSystem and a Diagram. See type hints of the subclasses for the specific argument and return types.
Source code in jaxonomy/framework/system_base.py
233 234 235 236 237 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 274 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 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 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 430 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 502 503 504 505 506 507 508 509 510 511 512 513 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 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 | |
dependency_graph
property
Retrieve (or create if necessary) the dependency graph for this system.
has_dirty_static_parameters
property
Check if any static parameters have been modified.
has_feedthrough_side_effects
abstractmethod
property
Check if the system includes any feedthrough calls to io_callback.
has_mass_matrix
abstractmethod
property
Returns True if any component of the system has a nontrivial mass matrix.
has_ode_side_effects
abstractmethod
property
Check if the ODE RHS for the system includes any calls to io_callback.
mass_matrix
abstractmethod
property
Mass matrix for this system.
Returns PyTree-structured data where each leaf is an (n, n) array. This is used for implicit integration methods (currently only BDF).
name_path
property
Get the human-readable path to this system. None if some names are not set.
name_path_str
property
Get the human-readable path to this system as a string.
ports
property
Dictionary of all ports in this system, indexed by name
root
property
Get the root system of the current system.
sorted_callbacks
property
Sort and return the callbacks for this system.
ui_id_path
property
Get the uuid node path to this system. None if some IDs are not set.
__deepcopy__(memo)
Deep-copy while keeping partially constructed copies hashable.
Subsystems reference themselves via callbacks; the default deepcopy order can
call :meth:__hash__ (via dict/set operations) before system_id exists
on the copy. Assign a new system_id immediately after memo registration.
Source code in jaxonomy/framework/system_base.py
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 | |
check_types(context, error_collector=None)
Perform any system-specific static analysis.
Source code in jaxonomy/framework/system_base.py
1282 1283 1284 | |
collect_inputs(context, port_indices=None)
Collect all current inputs for this system.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
ContextBase
|
root context for this system |
required |
port_indices
|
List[int]
|
list of input port indices to collect. If None (default), will return values from all ports. Otherwise will return a list of length(num_input_ports), where the values are None for ports not in the list. |
None
|
Returns:
| Type | Description |
|---|---|
List[Array]
|
List[Array]: list of all current input values |
Source code in jaxonomy/framework/system_base.py
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 | |
configure_output_port(port_index, callback, prerequisites_of_calc=None, default_value=None, event=None, cache_index=None)
Configure an output port of the system.
See declare_output_port for a description of the arguments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
port_index
|
int
|
index of the output port to configure |
required |
Returns:
| Type | Description |
|---|---|
|
None |
Source code in jaxonomy/framework/system_base.py
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 | |
context_factory()
Factory object for creating contexts for this system.
Should not be called directly - use system.create_context instead.
Source code in jaxonomy/framework/system_base.py
1286 1287 1288 1289 1290 1291 1292 | |
create_context(**kwargs)
Create a new context for this system.
The context will contain all variable information used in simulation/analysis/optimization, such as state and parameters.
Returns:
| Name | Type | Description |
|---|---|---|
ContextBase |
ContextBase
|
new context for this system |
Source code in jaxonomy/framework/system_base.py
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 | |
create_dependency_graph()
Create a dependency graph for this system.
Source code in jaxonomy/framework/system_base.py
1307 1308 1309 | |
declare_dynamic_parameter(name, default_value=None, shape=None, dtype=None, as_array=True)
Declare a numeric parameter for the system.
Parameters are declared in the system and accessed through the context to maintain separation of data ownership. This method creates an entry in the system's dynamic_parameters, recording the name, default value, and dependency ticket for later reference.
The default value will be used to initialize the context, so it will also serve as the initial value unless explicitly overridden. In the simplest cases, parameters could be stored as attributes of the LeafSystem, but declaring them has the advantage of moving the values to the context, allowing them to be traced by JAX rather than stored as static data. This means they can be differentiated, vmapped, or otherwise modified without re-compiling the simulation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the parameter. |
required |
default_value
|
Union[Array, Parameter]
|
The default value of the parameter. Parameters are used primarily internally for serialization and should not normally need to be used directly when implementing LeafSystems. Defaults to None. |
None
|
shape
|
ShapeLike
|
The shape of the parameter. Defaults to None. |
None
|
dtype
|
DTypeLike
|
The data type of the parameter. Defaults to None. |
None
|
as_array
|
bool
|
If True, treat the default_value as an array-like (cast if necessary). Otherwise, it will be stored as the default state without modification. |
True
|
Raises:
| Type | Description |
|---|---|
AssertionError
|
If the parameter with the given name is already declared. |
Notes
(1) Only one of shape and default_value should be provided. If
default_value is provided, it will be used as the initial value of the
continuous state. If shape is provided, the initial value will be a
zero vector of the given shape and specified dtype.
Source code in jaxonomy/framework/system_base.py
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 | |
declare_input_port(name=None, prerequisites_of_calc=None, units=None)
Add an input port to the system.
Returns the corresponding index into the system input_port_indices list Note that this is different from the callbacks index - typically it will make more sense to retrieve via system.input_ports[port_index], but
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
name of the new port. Defaults to None, which will use the default naming scheme for the system (e.g. "u_0") |
None
|
prerequisites_of_calc
|
List[DependencyTicket]
|
list of dependencies for the callback function. Defaults to None. |
None
|
units
|
Unit
|
physical unit of the signal carried on this
port (T-104 phase 1). Default |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
port index of the newly created port in |
Source code in jaxonomy/framework/system_base.py
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 | |
declare_output_port(callback, name=None, prerequisites_of_calc=None, default_value=None, event=None, cache_index=None, units=None)
Add an output port to the system.
This output port could represent any function of the context available to
the system, so a callback function is required. This function should have
the form
callback(context: ContextBase) -> Array
SystemBase implementations have some specific convenience wrappers, e.g.:
LeafSystem.declare_continuous_state_output
Diagram.export_output
Common cases are: - Feedthrough blocks: gather inputs and return some function of the inputs (e.g. a gain) - Stateful blocks: use LeafSystem.declare_(...)_state_output_port to return the value of a particular state - Diagrams: create and export a diagram-level port to the parent system using the callback function associated with the system-level port
Returns the corresponding index into the system output_port_indices list Note that this is different from the callbacks index - typically it will make more sense to retrieve via system.output_ports[port_index].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
Callable
|
computes the value of the output port given the root context. |
required |
name
|
str
|
name of the new port. Defaults to None, which will use the default naming scheme for the system (e.g. "y_0") |
None
|
prerequisites_of_calc
|
List[DependencyTicket]
|
list of
dependencies for the callback function. Defaults to None, which will
use the default dependencies for the system (all sources). This may
conservatively flag the system as having algebraic loops, so it is
better to be specific here when possible. This is done automatically
in the wrapper functions like |
None
|
default_value
|
Array
|
A default array-like value used to seed the context and perform type inference, when this is known up front. Defaults to None, which will use information propagation through the graph along with type promotion to determine an appropriate value. |
None
|
event
|
DiscreteUpdateEvent
|
A discrete update event associated with this output port that will periodically refresh the value that will be returned by the callback function. This makes the port act as a sample-and-hold rather than a direct function evaluation. |
None
|
cache_index
|
int
|
Index into the cache state component corresponding to the output port result, if the output port is of periodically-updated sample-and-hold type. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
port index of the newly created port |
Source code in jaxonomy/framework/system_base.py
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 | |
declare_static_parameter(name, value)
Declare a single static parameter for the system.
This is a convenience function for declaring a single static parameter.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
name of the parameter |
required |
value
|
Union[Array, Parameter]
|
value of the parameter |
required |
Source code in jaxonomy/framework/system_base.py
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 | |
declare_static_parameters(**params)
Declare a set of static parameters for the system.
These parameters are not JAX-traceable and therefore can't be optimized.
Examples of static parameters include booleans, strings, parameters used in shapes, etc.
The args should be a dict of name-value pairs, where the values are either strings, bool, arrays, or Parameters.
Typical usage:
class MyBlock(LeafSystem):
def __init__(self, param1=True, param2=1.0):
super().__init__()
self.declare_static_parameters(param1=param1, param2=param2)
Source code in jaxonomy/framework/system_base.py
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 | |
dependency_graph_factory()
Factory object for creating dependency graphs for this system.
Should not be called directly - use system.create_dependency_graph instead.
Source code in jaxonomy/framework/system_base.py
1299 1300 1301 1302 1303 1304 1305 | |
determine_active_guards(context)
abstractmethod
Determine active guards for zero-crossing events.
This method is responsible for evaluating and determining which
zero-crossing events are active based on the current system mode
and other conditions. This can be overridden to flag active/inactive
guards on a block-specific basis, for instance in a StateMachine-type
block. By default all guards are marked active at this point unless
the zero-crossing event was declared with a non-default start_mode, in
which case the guard is activated conditionally on the current mode.
For example, in a system with finite state transitions, where a transition from mode A to mode B is triggered by a guard function g_AB and the inverse transition is triggered by a guard function g_BA, this function would activate g_AB if the system is in mode A and g_BA if the system is in mode B. The other guard function would be inactive. If the zero-crossing event is not associated with a starting mode, it is considered to be always active.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
ContextBase
|
The root context containing the overall state and parameters. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
EventCollection |
EventCollection
|
A collection of zero-crossing events with active/inactive status updated based on the current system mode and other conditions. |
Source code in jaxonomy/framework/system_base.py
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 | |
eval_input(context, port_index=0)
Get the input for a given port.
This works by evaluating the callback function associated with the port, which will "pull" the upstream output port values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
ContextBase
|
root context for this system |
required |
port_index
|
int
|
index into |
0
|
Returns:
| Name | Type | Description |
|---|---|---|
Array |
Array
|
current input values |
Source code in jaxonomy/framework/system_base.py
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 | |
eval_time_derivatives(context)
Evaluate the continuous time derivatives for this system.
Given the root context, evaluate the continuous time derivatives, which must have the same PyTree structure as the continuous state.
In principle, this can be overridden by custom implementations, but
in general it is preferable to declare continuous states for LeafSystems
using declare_continuous_state, which accepts a callback function
that will be used to compute the derivatives. For Diagrams, the time
derivatives are computed automatically using the callback functions for
all child systems with continuous state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
ContextBase
|
root context of this system |
required |
Returns:
| Name | Type | Description |
|---|---|---|
StateComponent |
StateComponent
|
Continuous time derivatives for this system, or None if the system has no continuous state. |
Source code in jaxonomy/framework/system_base.py
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 | |
eval_zero_crossing_updates(context, events)
abstractmethod
Evaluate reset maps associated with zero-crossing events.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
ContextBase
|
The context for the system, containing the current state and parameters. |
required |
events
|
EventCollection
|
The collection of events to be evaluated (for example zero-crossing or periodic events for this system). |
required |
Returns:
| Name | Type | Description |
|---|---|---|
State |
State
|
The complete state with all updates applied. |
Notes
(1) Following the Drake definition, "unrestricted" updates are allowed to modify any component of the state: continuous, discrete, or mode. These updates are evaluated in the order in which they were declared, so it is possible (but should be strictly avoided) for multiple events to modify the same state component at the same time.
Each update computes its results given the current state of the system (the "minus" values) and returns the updated state (the "plus" values). The update functions cannot access any information about the "plus" values of its own state or the state of any other block. This could change in the future but for now it ensures consistency with Drake's discrete semantices:
More specifically, since all unrestricted updates can modify the entire state,
any time there are multiple unrestricted updates, the resulting states are
ALWAYS in conflict. For example, suppose a system has two unrestricted
updates, event1 and event2. At time t_n, event1 is active and event2
is inactive. First, event1 is evaluated, and the state is updated. Then
event2 is evaluated, but the state is not updated. Which one is valid?
Obviously, the event1 return is valid, but how do we communicate this to JAX?
The situation is more complicated if both event1 and event2 happen to be
active. In this case the states have to be "merged" somehow. In the worst
case, these two will modify the same components of the state in different ways.
The implementation updates the state in a local copy of the context (since both are immutable). This allows multiple unrestricted updates, but leaves open the possibility of multiple active updates modifying the state in conflicting ways. This should strictly be avoided by the implementer of the LeafSystem. If it is at all unclear how to do this, it may be better to split the system into multiple blocks to be safe.
(2) The events are evaluated conditionally on being marked "active" (indicating that their guard function triggered), so the entire event collection can be passed without filtering to active events. This is necessary to make the function calls work with JAX tracing, which do not allow for variable-sized arguments or returns.
Source code in jaxonomy/framework/system_base.py
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 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | |
get_feedthrough()
abstractmethod
Determine pairs of direct feedthrough ports for this system.
By default, the algorithm relies on the dependency tracking system to determine feedthrough, but this can be overridden by implementing this method directly in a subclass, for instance if the automatic dependency tracking is too conservative in determining feedthrough.
Returns:
| Type | Description |
|---|---|
List[Tuple[int, int]]
|
List[Tuple[int, int]]: A list of tuples (u, v) indicating that output port v has a direct dependency on input port u, resulting in a feedthrough path in the system. The indices u and v correspond to the indices of the input and output ports in the system's input and output port lists. |
Source code in jaxonomy/framework/system_base.py
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 | |
get_input_port(name)
Retrieve a specific input port by name.
Source code in jaxonomy/framework/system_base.py
885 886 887 888 889 890 891 892 893 | |
get_output_port(name)
Retrieve a specific output port by name.
Source code in jaxonomy/framework/system_base.py
907 908 909 910 911 912 | |
get_parameter(name)
Get a parameter value by name.
Checks dynamic parameters first, then static parameters. Values are
returned as concrete array-like / Python scalars via
:meth:Parameter.unwrap.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Parameter name on this system (not a dotted path). |
required |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
Source code in jaxonomy/framework/system_base.py
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 | |
handle_discrete_update(events, context, *, topological_order=False)
Compute and apply active discrete updates.
Given the root context, evaluate the discrete updates, which must have the same PyTree structure as the discrete states of this system. This should be a pure function, so that it does not modify any aspect of the context in-place (even though it is difficult to strictly prevent this in Python).
This will evaluate the set of events that result from declaring state or output
update events on systems using LeafSystem.declare_periodic_update and
LeafSystem.declare_output_port with an associated periodic update rate.
This is intended for internal use by the simulator and should not normally need to be invoked directly by users. Events are evaluated conditionally on being marked "active", so the entire event collection can be passed without filtering to active events. This is necessary to make the function calls work with JAX tracing, which do not allow for variable-sized arguments or returns.
For a discrete system updating at a particular rate, the update rule for a particular block is:
x[n+1] = f(t[n], x[n], u[n])
y[n] = g(t[n], x[n], u[n])
Additionally, the value y[n] is held constant until the next update from the point of view of other continuous-time or asynchronous discrete-time blocks.
Because each output y[n] may in general depend on the input u[n] evaluated
at the same time, the composite discrete update function represents a
system of equations. However, since algebraic loops are prohibited, the events
can be ordered and executed sequentially to ensure that the updates are applied
in the correct order. This is implemented in
SystemBase.sorted_callbacks.
Multirate systems work in the same way, except that the events are evaluated conditionally on whether the current time corresponds to an update time for each event.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events
|
EventCollection
|
collection of discrete update events |
required |
context
|
ContextBase
|
root context for this system |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ContextBase |
ContextBase
|
updated context with all active updates applied to the discrete state |
Source code in jaxonomy/framework/system_base.py
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 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | |
handle_zero_crossings(events, context)
Compute and apply active zero-crossing events.
This is intended for internal use by the simulator and should not normally need to be invoked directly by users. Events are evaluated conditionally on being marked "active", so the entire event collection can be passed without filtering to active events. This is necessary to make the function calls work with JAX tracing, which do not allow for variable-sized arguments or returns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events
|
EventCollection
|
collection of zero-crossing events |
required |
context
|
ContextBase
|
root context for this system |
required |
Returns:
| Name | Type | Description |
|---|---|---|
ContextBase |
ContextBase
|
updated context with all active zero-crossing events applied |
Source code in jaxonomy/framework/system_base.py
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 | |
initialize_static_data(context)
Initialize any context data that has to be done after context creation.
Use this to define custom auxiliary data or type inference that doesn't
get traced by JAX. See the ZeroOrderHold implementation for an example.
Since this is only applied during context initialization, it is allowed to
modify the context directly (or the system itself).
Typically this should not be called outside of the ContextFactory.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context
|
ContextBase
|
partially initialized context for this system. |
required |
Source code in jaxonomy/framework/system_base.py
1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 | |
list_parameters()
Return all parameters as a flat {name: value} mapping.
Dynamic parameters override static ones when names collide. Values are
unwrapped the same way as :meth:get_parameter.
Source code in jaxonomy/framework/system_base.py
1529 1530 1531 1532 1533 1534 1535 1536 | |
post_simulation_finalize()
Finalize the system after simulation has completed.
This is only intended for special blocks that need to clean up resources and close files.
Source code in jaxonomy/framework/system_base.py
348 349 350 351 352 | |
pprint(output=print, fancy=True)
Pretty-print the system and its hierarchy.
Source code in jaxonomy/framework/system_base.py
339 340 341 | |
recompute_port_cache(context)
Recompute all output ports and return them in a dictionary.
Source code in jaxonomy/framework/system_base.py
825 826 827 828 829 830 831 832 833 834 835 836 | |
SystemCallback
dataclass
A function associated with a system that has has specified dependencies.
This can include port update rules, discrete update functions, the right-hand-side of an ODE, etc. Storing these functions as SystemCallbacks allows the system, or a Diagram containing the system, to track dependencies across the system or diagram.
Attributes:
| Name | Type | Description |
|---|---|---|
system |
SystemBase
|
The system that owns this callback. |
ticket |
int
|
The dependency ticket associated with this callback. See DependencyTicket for built-in tickets. If None, a new ticket will be generated. |
name |
str
|
A short description of this callback function. |
prerequisites_of_calc |
List[DependencyTicket]
|
Direct prerequisites of the computation, used for dependency tracking. These might be built-in tickets or tickets associated with other SystemCallbacks. |
default_value |
Array
|
A dummy value of the same shape/dtype as the result, if known. If None, any type checking will rely on propagating upstream information via the callback. |
callback_index |
int
|
The index of this function in the system's list of associated callbacks. |
event |
Event
|
Optionally, the callback function may be associated with an event. If so, the associated trackers can be used to sort event execution order in addition to the regular callback execution order. For example, if an OutputPort is of sample-and-hold type, then this will be the event that periodically updates the output value. Default is None. |
Source code in jaxonomy/framework/cache.py
74 75 76 77 78 79 80 81 82 83 84 85 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 133 134 135 136 137 138 139 140 141 142 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 170 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 202 203 204 205 206 207 208 209 210 211 212 213 214 | |
calc(root_context)
Unconditionally evaluate the callback function.
This does not check the cache status, but will always recompute the value.
Typically eval should be preferred to calc to take advantage of caching
where possible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root_context
|
ContextBase
|
The root context used for the evaluation. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
The calculated value from the callback, expected to be a Array. |
Source code in jaxonomy/framework/cache.py
146 147 148 149 150 151 152 153 154 155 156 157 158 159 | |
eval(root_context)
Evaluate the callback function and return the calculated value.
Within a single top-level call, repeated evaluations of the same
callback against the same context are memoized (see _eval_memo
above) — this keeps eager evaluation of diagrams with fan-out /
reconvergence linear in graph size instead of exponential in
composition depth. Nothing is cached across top-level calls.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
root_context
|
ContextBase
|
The root context used for the evaluation. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
The calculated value from the callback, expected to be a Array. |
Source code in jaxonomy/framework/cache.py
161 162 163 164 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 194 195 196 197 | |
TriggerEdge
Allowed string values for TriggeredSubsystem.edge.
Source code in jaxonomy/framework/containers.py
139 140 141 142 143 144 145 146 147 148 | |
TriggeredSubsystem
Bases: LeafSystem
Container block: latch the submodel output on edge transitions (the child still RUNS every step — only the output is gated).
Important: this does not skip execution of the submodel on
non-triggered steps. The submodel is evaluated on every step so its
inputs participate in the JAX trace; the trigger only controls
whether a fresh result is latched into the held output. If you
need to actually skip computation between triggers, gate it yourself
with jax.lax.cond at the application level.
Phase-1 implementation runs the submodel on every step (so the inputs participate in the trace) but only latches a new output on an edge transition of the trigger signal. Between transitions the output holds the most recently latched value.
The trigger signal is sampled at sample_period. Edges are
detected by comparing the current trigger sample against the
previously-stored sample held in discrete state.
This is not the eventual zero-crossing-driven TriggeredSubsystem
described in the T-120 architecture notes (that requires hooking
into the continuous-time event detector); but it is functionally
correct for any sample-rate use case and matches the behaviour
documented in the test fixtures.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
submodel
|
Callable
|
Callable |
required |
n_inputs
|
int
|
Number of user inputs (NOT counting the trigger). |
1
|
edge
|
Literal['rising', 'falling', 'either']
|
|
RISING
|
sample_period
|
float
|
Period (seconds) at which the trigger signal is sampled and the latch is updated. Must be positive. |
0.0
|
initial_value
|
Latched output value before any edge has been detected. Defines output shape/dtype. |
0.0
|
|
name
|
Optional block name. |
required |
Limitations (phase 1):
- Trigger detection runs on the periodic sample grid, not on
continuous-time zero crossings. Trigger pulses shorter than
sample_period may be missed.
- The latch is a single discrete state; the submodel must
produce a single output array.
- The submodel runs on every output evaluation; only the
output is gated. Users who need to skip computation on
non-triggered steps should use jax.lax.cond at the
application level.
Source code in jaxonomy/framework/containers.py
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 430 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 502 503 504 505 506 507 508 509 510 511 512 513 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 | |
Unit
dataclass
Immutable SI dimensional value.
Units are compared by their dimension exponents and scale factor.
The optional name is informational (used in error messages) and is
not part of equality.
Source code in jaxonomy/framework/units.py
159 160 161 162 163 164 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 194 195 196 197 198 199 200 201 202 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 237 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 274 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 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 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 430 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 | |
from_dict(data)
classmethod
Construct a :class:Unit from a dict produced by
:meth:to_dict. Missing keys take their dataclass defaults so
the empty dict {} round-trips to Unit().
Source code in jaxonomy/framework/units.py
403 404 405 406 407 408 409 410 411 412 413 414 415 416 | |
from_json(json_str)
classmethod
Inverse of :meth:to_json.
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in jaxonomy/framework/units.py
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 | |
same_dimension_as(other)
True if exponents match (ignoring scale). Phase 1 doesn't use this for the connect check (which is strict-equal), but it's part of the public surface so Phase 2 can layer scalar-conversion warnings on top.
Source code in jaxonomy/framework/units.py
335 336 337 338 339 340 341 342 343 344 | |
summary()
Return a human-readable one-line summary of this Unit.
Designed for print() / display contexts where repr(unit)
is too terse. Includes the dimension exponents (with SI labels),
scale, offset, currency exponents, and the
physical_quantity tag when set.
Source code in jaxonomy/framework/units.py
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 | |
to_dict()
Return a JSON-friendly dict representation of this Unit.
Round-trips losslessly via :meth:from_dict. Keys are stable
across versions; new optional fields are always added with
defaults so older serialised forms continue to load.
The default value for any field is omitted from the output for
compactness — every legacy Unit() instance serialises to
{}.
Source code in jaxonomy/framework/units.py
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 | |
to_json(*, indent=None)
Serialise :meth:to_dict via :func:json.dumps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
indent
|
int | None
|
Optional JSON indent (default |
None
|
Source code in jaxonomy/framework/units.py
418 419 420 421 422 423 424 425 426 427 | |
UnitMismatchError
Bases: StaticError
Raised at diagram build time when two connected ports have incompatible units.
Attributes are populated through :class:StaticError so the regular
ErrorCollector / system-locator machinery still works.
Source code in jaxonomy/framework/units.py
150 151 152 153 154 155 156 | |
Variant
dataclass
A frozen description of N variant choices for build-time selection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
choices
|
Mapping[str, Callable[[], SystemBase]]
|
Mapping from choice name to a zero-argument builder callable.
Each callable, when invoked, must return a |
required |
default
|
str
|
Name of the choice to use when |
required |
name
|
Optional[str]
|
Optional human-readable label for diagnostics / logging. Does not affect resolution. |
None
|
Raises:
| Type | Description |
|---|---|
VariantError
|
If |
Source code in jaxonomy/framework/variants.py
133 134 135 136 137 138 139 140 141 142 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 170 171 172 173 174 175 176 177 178 179 180 181 182 | |
choice_names
property
Stable tuple of available choice names (for introspection / CLI).
VariantError
Bases: ValueError
Raised when a variant configuration is invalid or a selection is bad.
Source code in jaxonomy/framework/variants.py
124 125 | |
WhileLoop
Bases: LeafSystem
Container block: run body_fn until cond_fn is False.
WhileLoop wraps :func:jax.lax.while_loop with a built-in
iteration counter that caps execution at max_iter to guarantee
termination under jit.
The block declares an input port for the initial carry value
(port 0) plus n_inputs additional ports for upstream signals
that the loop body / condition can consume. A single output port
returns the carry after the loop exits (either because cond_fn
returned False, or because max_iter was hit).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
body_fn
|
Callable
|
Callable. Either |
required |
cond_fn
|
Callable
|
Callable. Either |
required |
max_iter
|
int
|
Positive integer cap on iterations. Required to keep traces bounded under jit. Defaults to 1000. |
1000
|
n_inputs
|
int
|
Number of additional upstream input ports (default 0).
When |
0
|
name
|
Optional block name. |
required |
Differentiability
jax.grad flows through the carry as long as body_fn and
cond_fn are pure. The number of iterations is data-dependent
and not differentiable; lax.while_loop is itself
non-differentiable in reverse mode (use jax.jvp for forward
mode, or refactor with :func:jax.lax.scan if you need a
reverse-mode-friendly bounded loop).
Notes
- On hitting
max_iterthe loop exits silently. Users who want a runtime warning shouldjax.debug.callbackfrombody_fnor test the post-loop carry. - The carry pytree structure must be invariant across
iterations (a
lax.while_looprequirement). - The condition is re-evaluated against the current upstream input values inside the loop trace — the inputs are captured once at output-evaluation time and held constant for the duration of the loop (the diagram doesn't re-tick during a single major step).
Source code in jaxonomy/framework/containers.py
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 | |
ZeroCrossingEvent
dataclass
Bases: Event
An event that triggers when a specified "guard" function crosses zero.
The event is triggered when the guard function crosses zero in the specified direction. In addition to the guard callback, the event also has a "reset map" which is called when the event is triggered. The reset map may update any state component in the system.
The event can also be defined as "terminal", which means that the simulation will terminate when the event is triggered. (TODO: Does the reset map still happen?)
The "direction" of the zero-crossing is one of the following: - "none": Never trigger the event (can be useful for debugging) - "positive_then_non_positive": Trigger when the guard goes from positive to non-positive - "negative_then_non_negative": Trigger when the guard goes from negative to non-negative - "crosses_zero": Trigger when the guard crosses zero in either direction - "edge_detection": Trigger when the guard changes value
Notes
This class should typically not need to be used directly by users. Instead,
declare the guard function and reset map on a LeafSystem using the
declare_zero_crossing method. The event will then be auto-generated for
simulation.
Source code in jaxonomy/framework/event.py
376 377 378 379 380 381 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 430 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 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 | |
handle(context)
Conditionally compute the result of the zero crossing callback
If the zero crossing is marked "inactive" via its event data attribute, the passthrough callback will be called instead of the update callback. Otherwise, the update callback will be called. The return types of both callbacks must match, but the specific type will depend on the kind of event.
Source code in jaxonomy/framework/event.py
453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 | |
should_trigger()
Determine if the event should trigger based on the stored guard values.
Source code in jaxonomy/framework/event.py
449 450 451 | |
ZeroCrossingTriggeredSubsystem
Bases: LeafSystem
Container block: latch the submodel output at zero-crossings.
Like :class:TriggeredSubsystem, but uses the framework's continuous
zero-crossing detector rather than a periodic sample grid. The
submodel fires exactly when the trigger signal crosses zero in the
configured direction — this gives sub-sample-period precision for
the latched event time, which is the property normally expected
from a triggered subsystem driven by a continuous signal.
Wiring matches :class:TriggeredSubsystem:
- Input port 0 is the trigger signal (a continuous scalar; the block monitors its sign).
- Input ports 1..n_inputs are the submodel inputs.
- The single output port returns the most recently latched
submodel output (initialized to
initial_value).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
submodel
|
Callable
|
Callable |
required |
n_inputs
|
int
|
Number of user inputs (NOT counting the trigger). |
1
|
edge
|
Literal['rising', 'falling', 'either']
|
|
RISING
|
initial_value
|
Latched output value before the first crossing fires. Also defines the output shape/dtype. |
0.0
|
|
name
|
Optional block name. |
required |
Differentiability
jax.grad flows through the submodel inputs along the path
through the latch (so when the latched value depends on a
differentiable input, the gradient propagates). The trigger
signal itself is consumed by the zero-crossing event detector;
the gradient through the discontinuity at the firing instant
is zero by design (the latched value is constant between
crossings).
Notes
- The framework localizes the zero crossing to within the
integrator's tolerance, so the latched output reflects the
submodel inputs at the crossing instant, not at the next
periodic sample. Compare with the phase-1
:class:
TriggeredSubsystem, which can only resolve the edge to the nearestsample_period. - The latch is a single discrete-state component; the submodel must produce a single output array of fixed shape.
- This is a leaf block (no nested mode machinery), so the
"hold between crossings"semantics fall out naturally: the output port simply returnsstate.discrete_state.
Source code in jaxonomy/framework/containers.py
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 | |
ForEach(submodel, n, n_inputs=1, in_axes=None, name=None)
Container block: evaluate a submodel n times in parallel.
ForEach is a block-diagram-vocabulary alias for the existing
:class:jaxonomy.library.ReplicatedFunction (T-010). It exists so
that users familiar with the ForEach block name can find it
without paying a duplication tax: the implementation
is exactly :class:ReplicatedFunction under the hood.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
submodel
|
Callable
|
Callable |
required |
n
|
int
|
Number of replicas (the iteration count). |
required |
n_inputs
|
int
|
Number of input ports the block declares. |
1
|
in_axes
|
As in :func: |
None
|
|
name
|
str | None
|
Optional block name. |
None
|
Returns:
| Type | Description |
|---|---|
|
A configured :class: |
|
|
wired into a :class: |
Source code in jaxonomy/framework/containers.py
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 | |
apply_variant_config(diagram, **overrides)
Return a copy of diagram with named variants reconfigured.
Walks the diagram tree, finds every subsystem that was produced by
:func:select_variant from a named Variant, and -- for each
override_name=choice keyword -- replaces matching subsystems with
a freshly-built copy from select_variant(variant, name=choice).
All other diagram structure (non-variant blocks, connections,
exported ports) is preserved.
The original diagram is not modified.
Example::
builder = DiagramBuilder()
ctrl = select_variant(controller_variant, name="pid") # default
plant = select_variant(plant_variant, name="lti")
builder.add(ctrl)
builder.add(plant)
...
diagram = builder.build()
# Reconfigure post-build:
runtime_a = apply_variant_config(diagram, controller="pid", plant="lti")
runtime_b = apply_variant_config(diagram, controller="lqr", plant="lti")
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diagram
|
A built |
required | |
**overrides
|
Map from a variant's |
{}
|
Returns:
| Type | Description |
|---|---|
|
A new |
|
|
If |
|
|
copy of |
|
|
meth: |
Raises:
| Type | Description |
|---|---|
VariantError
|
If an override name does not match any variant in
the diagram, or if the requested choice is not in that
variant's |
Source code in jaxonomy/framework/variants.py
339 340 341 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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 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 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | |
are_units_compatible(src, dst)
Return True if a connection from src to dst should be
allowed under the Phase-1 rules:
- Either side being
None(unset) is always OK. - If both sides are :class:
BusUnit, compatible iff every shared field's :class:Unitis pair-wise compatible AND the field sets match. ABusUniton one side andNoneon the other is always OK (default-off byte-equivalence with the no-units bus). - Otherwise, both sides must be plain :class:
Unit; either being :data:dimensionlessis OK, else units must be equal.
Scalar conversion (Phase 2) is layered on top by
:func:assert_units_compatible_with_scale — see there.
Source code in jaxonomy/framework/units.py
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 | |
assert_unit_compatible(src, dst, *, src_label='source port', dst_label='destination port')
Raise :class:UnitMismatchError if the two units are not
Phase-1-compatible. See :func:are_units_compatible.
The labels are interpolated into the message so the caller (typically
:meth:DiagramBuilder.connect) can name both ports.
Source code in jaxonomy/framework/units.py
1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 | |
clear_fx_rates()
Empty the FX rate table. Tests use this to keep their state isolated; production code should rarely need to call it.
Source code in jaxonomy/framework/units.py
779 780 781 782 783 784 | |
convert_currency(value, from_unit, to_unit)
Convert a numeric value carried in from_unit to the
equivalent value in to_unit using the current FX rate table.
Self-conversion (same currency on both sides) is a no-op and
returns the value unchanged. Cross-currency conversion looks up
the rate via :func:get_fx_rate and multiplies; a missing rate
raises :class:KeyError.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
Numeric value (Python scalar, NumPy array, JAX array).
The helper only uses |
required | |
from_unit
|
'Unit | str'
|
Source currency, either a :class: |
required |
to_unit
|
'Unit | str'
|
Destination currency, ditto. |
required |
Returns:
| Type | Description |
|---|---|
|
|
Raises:
| Type | Description |
|---|---|
UnitMismatchError
|
if either argument carries non-currency dimensions (e.g. seconds), so the conversion is undefined. |
KeyError
|
if the relevant FX rate has not been registered. |
Example:
>>> set_fx_rate("USD", "EUR", 0.92)
>>> convert_currency(100.0, usd, eur)
92.0
Source code in jaxonomy/framework/units.py
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 | |
derived_unit(name, symbol=None, components=None)
Define a new derived :class:Unit from existing components.
This is a convenience constructor for users who want to spell a
composite unit once (with a friendly name) rather than recomposing
its base components at every port declaration site. The returned
:class:Unit has the same (dims, scale, offset) as
components — it is therefore equal (under Unit.__eq__) to
any other unit with matching dimensions and scale — but carries
a custom name for friendlier error messages and pprint output.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Long-form descriptive name (e.g. |
required |
symbol
|
str | None
|
Short-form printable symbol (e.g. |
None
|
components
|
'Unit | None'
|
A :class: |
None
|
Returns:
| Type | Description |
|---|---|
'Unit'
|
A fresh :class: |
'Unit'
|
|
'Unit'
|
set to |
Raises:
| Type | Description |
|---|---|
TypeError
|
if |
UnitMismatchError
|
if |
Example:
>>> from jaxonomy.framework.units import (
... derived_unit, meter, newton,
... )
>>> torque = derived_unit("torque", "N·m", meter * newton)
>>> torque.dims == (1, 2, -2, 0, 0, 0, 0)
True
>>> torque == meter * newton
True
Source code in jaxonomy/framework/units.py
844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 | |
flatten_diagram(diagram)
Flatten a nested Diagram into a single-depth Diagram.
All intermediate sub-Diagrams are dissolved. The resulting Diagram has: - nodes: all LeafSystem instances from the original tree - connection_map: remapped to only reference leaf-to-leaf connections - exported inputs/outputs: preserved (still reference the same leaf ports)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diagram
|
Diagram
|
The (possibly nested) Diagram to flatten. |
required |
Returns:
| Type | Description |
|---|---|
Diagram
|
A new single-depth Diagram with all original LeafSystems as direct |
Diagram
|
children and all connections resolved to the leaf level. |
Source code in jaxonomy/framework/flatten.py
136 137 138 139 140 141 142 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 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 | |
get_active_variant(diagram, variant_name)
Return the currently-selected choice for the named variant.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diagram
|
A built |
required | |
variant_name
|
str
|
The human-readable label of the variant to look
up (the |
required |
Returns:
| Type | Description |
|---|---|
|
The name of the active choice (a string in |
|
|
|
|
|
given name is found in the diagram. The |
|
|
CLI / introspection code treat "no such variant" as a soft |
|
|
miss; use :func: |
|
|
for unknown names. |
Source code in jaxonomy/framework/variants.py
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | |
get_fx_rate(from_currency, to_currency)
Return the previously-set FX rate from from_currency to
to_currency. Self-rates are always 1.0 even when unset.
Raises:
| Type | Description |
|---|---|
KeyError
|
if no rate has been set for the requested pair AND the two codes differ. |
UnitMismatchError
|
if either argument is not a pure currency. |
Source code in jaxonomy/framework/units.py
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 | |
get_variant_choices(diagram, variant_name)
Return the choice names of the named variant in diagram.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diagram
|
A built |
required | |
variant_name
|
str
|
The human-readable label of the variant to look
up (the |
required |
Returns:
| Type | Description |
|---|---|
tuple
|
A tuple of choice names ( |
tuple
|
insertion order. |
Raises:
| Type | Description |
|---|---|
VariantError
|
If no variant with the given name is found in the
diagram. Anonymous Variants (built without |
Source code in jaxonomy/framework/variants.py
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 | |
list_variants(diagram)
List every variant point found in a (possibly nested) diagram.
Walks diagram recursively and returns a metadata triple for
every subsystem that was produced by :func:select_variant. Each
triple has the shape (name, choice_names, active_choice):
nameis the variant's human-readable label (Variant.name).Nonefor anonymous Variants.choice_namesis the stable tuple of available choice names (Variant.choice_names).active_choiceis the name of the choice currently bound at this point in the diagram.
Iteration order follows the diagram's tree-traversal order (parent
before children, siblings in registration order). If the same
Variant instance is reused at multiple points in the diagram,
each occurrence yields its own entry — callers that want a deduped
view should collapse on name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diagram
|
A built |
required |
Returns:
| Type | Description |
|---|---|
list[tuple]
|
A list of |
list[tuple]
|
if |
Source code in jaxonomy/framework/variants.py
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 502 503 504 505 506 507 508 509 510 511 512 513 514 515 | |
next_dependency_ticket()
Create a new unique dependency ticket using the next available value.
Source code in jaxonomy/framework/dependency_graph.py
77 78 79 | |
parameters(static=None, dynamic=None)
Decorator to apply to a system class to declare static or dynamic parameters.
Source code in jaxonomy/framework/system_decorators.py
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 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 | |
select_variant(variant, name=None)
Resolve a Variant at build time and return the active sub-system.
Only the chosen builder is invoked; the others are never called. This matches the "active variant only" code-generation behavior familiar from established block-diagram tools -- nothing about the unselected branches enters the JIT trace, the parameter pytree, or the diagram's registered-systems list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
variant
|
Variant
|
The |
required |
name
|
Optional[str]
|
Name of the choice to activate. If |
None
|
Returns:
| Type | Description |
|---|---|
SystemBase
|
The |
Raises:
| Type | Description |
|---|---|
VariantError
|
If |
Source code in jaxonomy/framework/variants.py
190 191 192 193 194 195 196 197 198 199 200 201 202 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 237 238 239 | |
set_fx_rate(from_currency, to_currency, rate)
Record an FX rate so that one unit of from_currency equals
rate units of to_currency.
Both directions are written: setting USD→EUR at 0.92 simultaneously
sets EUR→USD at 1.0 / 0.92 so round-trips are exact under the
floating-point reciprocal. A zero or non-finite rate is rejected
(FX rates must be positive finite numbers).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
from_currency
|
'Unit | str'
|
Source currency, either a :class: |
required |
to_currency
|
'Unit | str'
|
Destination currency, ditto. |
required |
rate
|
float
|
Strictly positive multiplicative conversion factor. |
required |
Raises:
| Type | Description |
|---|---|
ValueError
|
if |
UnitMismatchError
|
if either argument is not a pure currency. |
Example:
>>> set_fx_rate("USD", "EUR", 0.92)
>>> get_fx_rate(usd, eur)
0.92
>>> # Self-rate is always 1.0 and need not be set explicitly.
>>> get_fx_rate(usd, usd)
1.0
Source code in jaxonomy/framework/units.py
692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | |
submodel_function(system, output_ports=None, input_ports=None, auto_seed=True)
Wrap system's ports as a pure function of (context, *inputs).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
system
|
'SystemBase'
|
The |
required |
output_ports
|
'Sequence[OutputPort] | None'
|
Output ports whose values to return. Defaults to
all of |
None
|
input_ports
|
'Sequence[InputPort] | None'
|
Input ports that the closure will feed. Defaults to
all of |
None
|
auto_seed
|
bool
|
If True (default), any input port in |
True
|
Returns:
| Type | Description |
|---|---|
Callable
|
|
Callable
|
is selected the return is a scalar / array; otherwise a tuple |
Callable
|
in |
Example::
bld = jaxonomy.DiagramBuilder()
plant = bld.add(MyPlant())
bld.export_input(plant.input_ports[0], name="u")
bld.export_output(plant.output_ports[0], name="y")
diagram = bld.build()
f = jaxonomy.submodel_function(diagram)
ctx = diagram.create_context() # auto-seeded placeholders
y = f(ctx, u)
dy_du = jax.grad(lambda u: f(ctx, u))(u0)
y_batch = jax.vmap(f, in_axes=(None, 0))(ctx, u_batch)
Performance envelope (T-008, follow-up finding 2026-05-16):
Each call invokes the diagram's full evaluation machinery —
port-fix context managers, dependency-tracked output evaluation,
cache invalidation. That overhead is fine for one-shot
rollouts, batched evaluation (where the cost amortises
across the batch via jax.vmap), and gradient computation
via jax.grad (the closure is traced once, then the
compiled XLA program runs at native speed).
It is **not** fine for tight Python-side loops that call ``f``
thousands of times per simulated second — typical MPC inner
loops where the prediction model is re-evaluated at every
sample of a ``jax.lax.scan``-style rollout. There the per-call
Python overhead dominates and the wall-clock blows up by 100×
or more relative to closing over the underlying primitive
directly (e.g. ``interp_2d``, ``lookup_table_nd``, or a
hand-rolled JAX function). The canonical workaround in that
case is to skip ``submodel_function`` entirely for the inner
loop and call the primitive directly inside the scan body. See
``docs/examples/engine_map_fitting_to_mpc.ipynb`` for an
example of the hand-rolled-scan pattern.
Rule of thumb: if the closure will be invoked from a
Python-level loop more than ~100 times per simulation, profile
first. ``jax.jit(f)`` + ``jax.vmap`` over the entire batch
usually beats a Python loop by orders of magnitude.
Source code in jaxonomy/framework/submodel.py
83 84 85 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 133 134 135 136 137 138 139 140 141 142 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 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 | |
variant_subsystem(choices, name=None, default=None)
Build a resolver closure for a one-shot variant point.
Convenience wrapper around Variant + select_variant for the
common case::
controller = variant_subsystem(
choices={
"pid": lambda: build_pid(),
"lqr": lambda: build_lqr(),
},
default="pid",
)
# Later, at "configure" time:
active = controller(name="lqr") # returns the lqr Diagram
active = controller() # returns the pid Diagram (default)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
choices
|
Mapping[str, Callable[[], SystemBase]]
|
See |
required |
name
|
Optional[str]
|
See |
None
|
default
|
Optional[str]
|
Choice name to use when the returned closure is called without
an argument. If |
None
|
Returns:
| Type | Description |
|---|---|
Callable[..., SystemBase]
|
A closure |
Callable[..., SystemBase]
|
resolves to a freshly-built sub-system for the named choice. |
Source code in jaxonomy/framework/variants.py
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 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 | |