Field Registry and Compute¶
FieldDataset.compute("beta") dispatches through this registry: a Recipe
names the derived function, the canonical field names it consumes, and the
quantity type of what it returns. RECIPES is the registry itself, exposed
read-only.
register_recipe / unregister_recipe extend it at runtime, and
SPECIES_TEMPLATES synthesizes per-species entries (omega_p_s2,
lambda_D_s3, ...) on demand rather than enumerating every species up front.
Adding a quantity goes through register_recipe, not Recipe. It takes
the name and quantity_type alongside the function and its inputs, and
registers both the recipe and the field metadata, so compute(), in_si()
and field_info() all light up together:
register_recipe(
"e_mag_fraction",
func=lambda e_b, e_k: e_b / (e_b + e_k),
fields=("e_B", "e_k"), # stored fields or other derived names
quantity_type="dimensionless",
)
Recipe is the record the registry stores. It carries neither the name nor
the quantity type — those are registry keys — and is exported for the
cross-language export in pypic.codegen, not for registration.
For a single array on a single dataset, FieldDataset.with_field is the
lighter option: it stamps the metadata into that dataset's attrs and leaves
the global registry alone. examples/advanced_calculations.py runs both.
field_dependencies reports what a quantity needs, which is what lets
Simulation.read load exactly the fields a later compute() call will
require. available_quantities() takes no arguments and lists every registered
quantity name and alias, excluding the per-species names synthesized on
demand.
Recipes marked supports_relativistic=True receive c automatically when
physics.relativistic is set in the dataset config — see
Equations § 8.
compute
¶
String-based dispatch for derived quantities on FieldDataset.
Maps short names ("|B|", "beta", "v_A", ...) to pure functions
in derived.py, diagnostics.py, and operators.py. The tables
live in pypic._recipes; this module resolves names, executes recipes,
and owns the registration API. FieldDataset sits below it and reaches
compute_field through a deferred import.
Recipe
dataclass
¶
Describes how to derive one quantity from existing fields.
Mapped from a canonical name in RECIPES. func consumes
the dependency arrays declared in fields (in order) and returns
the derived array. The remaining attributes describe what extras
the dispatcher should inject (grid, gamma, species args, …) before
calling func.
Source code in src/pypic/_recipes.py
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 | |
SpeciesArgs
¶
Bases: StrEnum
Describes which species parameters a dynamic recipe needs.
Source code in src/pypic/_recipes.py
24 25 26 27 28 29 30 | |
SpeciesTemplate
dataclass
¶
Template for species-dependent derived quantities.
Used to dynamically synthesize recipes for species index >= 2, where static registry entries don't exist.
Source code in src/pypic/_recipes.py
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | |
compute_field(name, dataset, _depth=0)
¶
Compute a derived quantity by name from a FieldDataset.
If name is already present in the dataset, returns it directly. Otherwise dispatches to the registered pure function, recursively resolving any intermediate dependencies.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Field or derived quantity name (e.g. |
required |
dataset
|
FieldDataset
|
Source data. |
required |
Returns:
| Type | Description |
|---|---|
FloatArray
|
Computed array in code units. |
Raises:
| Type | Description |
|---|---|
KeyError
|
If name is unknown and not in the dataset. |
ValueError
|
If required species or physics info is missing. |
GeometryUnsupportedError
|
If the recipe requires spatial derivatives and the dataset
grid is non-Cartesian or not three-dimensional. Subclass of
|
RecursionError
|
If dependency chain exceeds depth limit. |
Examples:
Dependencies resolve recursively — v_A needs |B|, which the
dataset does not carry either:
>>> import numpy as np
>>> from pypic import FieldDataset, GridInfo
>>> from pypic.units import Normalization
>>> grid = GridInfo(dimensions=(2, 2, 2), spacing=(1.0, 1.0, 1.0))
>>> ones = np.ones((2, 2, 2))
>>> ds = FieldDataset.from_arrays(
... {"B_1": 3.0 * ones, "B_2": 4.0 * ones, "B_3": 0.0 * ones,
... "rho_m": 4.0 * ones},
... grid, Normalization.identity(),
... )
>>> float(compute_field("v_A", ds)[0, 0, 0]) # |B| / sqrt(rho_m)
2.5
Source code in src/pypic/compute.py
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 | |
field_si_factor(name, normalization)
¶
Return the SI conversion factor for a field or derived quantity.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Field or derived quantity name. |
required |
normalization
|
Normalization
|
Active normalization. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Multiplicative factor: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the quantity type for name is unknown. |
Examples:
>>> from pypic.units import Normalization
>>> norm = Normalization.mhd_standard(6.371e6, 1.67e-17, 5.0e-9)
>>> field_si_factor("B_1", norm) # b_field type resolves to B_ref
5e-09
Source code in src/pypic/compute.py
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 | |
display_unit_factor(unit_str)
¶
Return the SI value of a display unit string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
unit_str
|
str
|
Unit string (e.g. |
required |
Returns:
| Type | Description |
|---|---|
float
|
Value of one display unit in SI. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If unit_str is not recognized. |
Examples:
>>> display_unit_factor("nT"), display_unit_factor("km/s")
(1e-09, 1000.0)
Source code in src/pypic/compute.py
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 | |
available_quantities()
¶
Return sorted list of registered quantity names and aliases.
Does not include dynamically synthesized per-species quantities
(e.g. "omega_p_s2", "T_s3"), which are also computable
via compute_field.
Returns:
| Type | Description |
|---|---|
list[str]
|
|
Examples:
>>> names = available_quantities()
>>> "beta" in names, "v_A" in names, "omega_p_s2" in names
(True, True, False)
Source code in src/pypic/compute.py
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 | |
field_dependencies(name, _depth=0)
¶
Return the raw field names needed to compute name.
Recursively walks the compute recipe graph. If name has no recipe
(i.e. it is a raw field), returns {name}.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Field or derived quantity name (e.g. |
required |
Returns:
| Type | Description |
|---|---|
set[str]
|
Leaf field names that must be present in the dataset. |
Examples:
>>> sorted(field_dependencies("v_A"))
['B_1', 'B_2', 'B_3', 'rho_m']
>>> sorted(field_dependencies("rho_m")) # a raw field is its own leaf
['rho_m']
Source code in src/pypic/compute.py
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 | |
compute_with_siblings(name, dataset)
¶
Compute name and, for a vector component, its siblings in one call.
Component recipes (S_1, curl_B_2, V_s2_perp_3) share one
tuple-returning function, so evaluating it once yields every
component. Scalar recipes return a single entry keyed by name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Field or derived quantity name (canonical or alias). |
required |
dataset
|
FieldDataset
|
Source of the dependency fields. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, FloatArray]
|
One entry for a scalar recipe; one per component, keyed by the registry names, for a vector recipe. |
Source code in src/pypic/compute.py
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 | |
register_recipe(name, func, fields, quantity_type, *, needs_grid=False, needs_gamma=False, needs_c=False, long_name='', latex='')
¶
Register a custom derived quantity.
Registers both the computation recipe and the field metadata,
so compute(), in_si(), field_info(), and
with_derived() all work for the custom field.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Quantity name (e.g. |
required |
func
|
Callable
|
Pure function: takes arrays (one per field in fields), plus grid spacing if needs_grid, plus gamma if needs_gamma, plus c if needs_c. Returns a single array. |
required |
fields
|
tuple[str, ...]
|
Input field names (canonical or derived). Resolved recursively at compute time. |
required |
quantity_type
|
QuantityType | str
|
Physical quantity type for SI conversion. |
required |
needs_grid
|
bool
|
If |
False
|
needs_gamma
|
bool
|
If |
False
|
needs_c
|
bool
|
If |
False
|
long_name
|
str
|
Human-readable label for plot titles. |
''
|
latex
|
str
|
LaTeX symbol for plot labels. |
''
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If name already exists in the recipe registry. |
Examples:
>>> import numpy as np
>>> register_recipe(
... "e_mag_ratio",
... func=lambda eb, ee: eb / (eb + ee),
... fields=("e_B", "e_E"),
... quantity_type="dimensionless",
... long_name="Magnetic-to-total EM energy ratio",
... )
>>> "e_mag_ratio" in available_quantities()
True
>>> unregister_recipe("e_mag_ratio")
Source code in src/pypic/compute.py
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 | |
unregister_recipe(name)
¶
Remove a custom derived quantity.
Removes both the computation recipe and the field metadata.
Raises:
| Type | Description |
|---|---|
KeyError
|
If name is not registered. |
Source code in src/pypic/compute.py
698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 | |