Skip to content

feat: Added USDA converter - #50

Draft
IsNeron wants to merge 1 commit into
mainfrom
feat/usda-converter
Draft

feat: Added USDA converter#50
IsNeron wants to merge 1 commit into
mainfrom
feat/usda-converter

Conversation

@IsNeron

@IsNeron IsNeron commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

@IsNeron
IsNeron requested a review from mentaljam August 21, 2026 13:46
@IsNeron IsNeron self-assigned this Aug 21, 2026

@mentaljam mentaljam left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requested redesign: texture-class adapters

This change should not introduce a generated, Python-only utility module plus
per-PTF input_adapters.usda_texture status metadata. The proposed utility is
a fixed table of twelve USDA classes, and the current metadata is not used by
any PTF. As implemented, users must call the converter themselves and then
pass numeric fractions to a PTF; that exposes an implementation detail and
does not provide a cross-target PTF feature.

Please redesign this as a first-class input type and a compiler-lowered
derived-input mechanism.

Specification model

  1. Add an adapter registry under specs/adapters/. Each adapter has its own
    schema and defines its logical input and output contract. The USDA adapter
    defines one strict usda_texture_class input and the numeric sand,
    silt, and clay outputs.
  2. Make registered adapter input types available to all PTF specifications.
    A PTF may explicitly declare a parameter with type usda_texture_class.
  3. Let a PTF explicitly bind adapter outputs to derived numeric inputs used by
    its formula. For example, a texture_class parameter can be lowered to
    derived sand, silt, and clay values. Do not infer this from variable
    names occurring in the formula.
  4. Require source-backed scientific evidence on the PTF binding: it must
    establish that the published PTF's particle-size definitions are compatible
    with this adapter. An adapter is available to every PTF, but no PTF may use
    it without this explicit claim.
  5. Preserve a published categorical texture-class predictor as categorical.
    Do not replace it with representative fractions unless the source actually
    supports that model transformation.

The following is an illustrative target syntax, not a request to accept this
exact YAML before the schema and IR are designed:

inputs:
  - name: texture_class
    type: usda_texture_class

derived_inputs:
  sand: { adapter: usda_texture, input: texture_class, component: sand }
  silt: { adapter: usda_texture, input: texture_class, component: silt }
  clay: { adapter: usda_texture, input: texture_class, component: clay }

implementation:
  variables:
    - name: theta_33
      expr: ...

texture_class is the only public input in this example. Its declared type
selects the strict USDA class contract. Each derived_inputs entry explicitly
states that one numeric formula symbol comes from the named component of the
usda_texture adapter applied to that input. The formula may consequently
refer to sand, silt, and clay as ordinary scalar symbols. It does not
accept them from the caller, and the generator does not guess the binding from
their names. theta_33 is only a placeholder for the normal, source-backed
PTF expression.

The semantic IR should contain the explicit derived-input bindings. Renderers
then insert the target-local adapter call before evaluating the normal numeric
formula. sand, silt, and clay therefore remain ordinary scalar symbols
in the formula and do not become hidden or magical inputs.

Target implementations

The adapter implementation is a small fixed table and should be handwritten
once in each retained target. It is not necessary to generate that table from
YAML. The generator's responsibility is to lower declared adapter bindings
and render calls to the target-local implementation.

The public PTF API accepts texture_class; users should not have to manually
compose a public conversion call with a numerical PTF call. A public standalone
converter may still be exported as a convenience API, but it has the same
strict contract and is not the primary integration mechanism.

Python must implement the adapter in the direct CPython/NumPy extension, not
as a Python dictionary lookup or numpy.vectorize wrapper. PTFs accepting
texture classes must retain array inputs, broadcasting, and out behaviour.
The C extension may use compact internal class codes, but it must accept the
documented exact Unicode class values at its public boundary.

Python contract

The generated Python type surface should use an exact Literal[...] union of
the twelve canonical lowercase USDA names. There should be no StrEnum,
case-folding, trimming, hyphen/underscore substitution, aliases, abbreviations,
or fuzzy matching. Invalid input is a caller error: the API must enforce the
contract rather than repair input data.

This is a semantic redesign, so the current generated module, its generated
tests, the one-off USDA utility specification/schema, and the current
input_adapters.usda_texture status model should be replaced rather than
extended.

@mentaljam

Copy link
Copy Markdown
Contributor

One further clarification on the runtime representation and where string parsing should live.

The generated PTF core should operate only on the target's native categorical representation. String parsing should not be part of the generated PTF implementation or adapter lowering.

For the retained targets:

  • C/C++/CPython should use a compact uint8_t representation for USDA texture classes.
  • Rust should use a normal idiomatic UsdaTexture enum without any representation like #[repr(u8)].
  • A prepared Python texture array should therefore contain validated class codes, not strings or materialized sand/silt/clay arrays.

Codegen should generate the categorical type/constants and the mapping from that categorical representation to representative fractions. For example, C/C++/CPython may use a generated lookup table, while Rust may use an idiomatic generated conversion such as From<UsdaTexture> for Fractions.

String-to-category conversion is a target-level convenience and should be handwritten where useful rather than modeled in the specification or generalized in codegen. This keeps the generator focused on scientific data and computation rather than target-specific text handling.

For example, the Rust helper can simply implement FromStr with a direct match on the twelve canonical names:

impl FromStr for UsdaTexture {
    type Err = ParseUsdaTextureError;

    fn from_str(value: &str) -> Result<Self, Self::Err> {
        match value {
            "sand" => Ok(Self::Sand),
            "loamy sand" => Ok(Self::LoamySand),
            "sandy loam" => Ok(Self::SandyLoam),
            // ...
            _ => Err(ParseUsdaTextureError),
        }
    }
}

Similarly, CPython can have a handwritten parser optimized for its actual input representation.

The intended separation is therefore:

external textual representation
        |
        | target-specific handwritten parser
        v
native categorical representation
        |
        | generated mapping
        v
representative sand/silt/clay
        |
        v
generated PTF formula

The mandatory preparation step discussed above remains unchanged: raw string arrays are converted once into the prepared categorical representation, and PTFs accept only that prepared representation. This avoids repeated string parsing while keeping both the specification model and code generation simple.

@IsNeron
IsNeron marked this pull request as draft August 24, 2026 12:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants