Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 59 additions & 1 deletion docs/guides/inventories.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,70 @@ tree_inventory = inventories.create_tree_inventory_from_treemap(
},
{
"conditions": [{"attribute": "DIA", "operator": "lt", "value": 10}],
"actions": [{"attribute": "all", "modifier": "remove"}]
"actions": [{"modifier": "remove"}]
}
]
)
```

### Using Expression-Based Conditions

For more complex filtering, you can use arithmetic expressions that combine multiple tree fields. This eliminates the need to download, filter with pandas, and re-upload data.

**Remove trees with short crowns** (crown length < 1m):

```python
tree_inventory = inventories.create_tree_inventory_from_treemap(
modifications={
"conditions": [{
"attribute": "expression",
"expression": "HT * CR", # Crown length = height × crown ratio
"operator": "lt",
"value": 1.0
}],
"actions": [{"modifier": "remove"}]
}
)
```

**Remove unrealistic slender trees** (height/diameter ratio > 100):

```python
tree_inventory = inventories.create_tree_inventory_from_treemap(
modifications={
"conditions": [{
"attribute": "expression",
"expression": "HT / DIA", # Slenderness ratio
"operator": "gt",
"value": 100.0
}],
"actions": [{"modifier": "remove"}]
}
)
```

**Combine field and expression conditions** (remove tall, slender Douglas-fir):

```python
tree_inventory = inventories.create_tree_inventory_from_treemap(
modifications={
"conditions": [
{"attribute": "SPCD", "operator": "eq", "value": 202}, # Douglas-fir
{"attribute": "expression", "expression": "HT / DIA", "operator": "gt", "value": 100}
],
"actions": [{"modifier": "remove"}]
}
)
```

**Supported expression fields**: `HT` (height), `DIA` (diameter), `CR` (crown ratio)
**Supported operators**: `+`, `-`, `*`, `/`, `()`
**Common patterns**:
- Crown length: `HT * CR`
- Crown base height: `HT * (1 - CR)`
- Slenderness ratio: `HT / DIA`
- Average metric: `(HT + DIA) / 2`

## How to Apply Forest Management Treatments

To thin to a target basal area:
Expand Down
2 changes: 2 additions & 0 deletions fastfuels_sdk/client_library/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@
"TreeInventoryModificationCondition",
"TreeInventoryModificationDIAAction",
"TreeInventoryModificationDIACondition",
"TreeInventoryModificationExpressionCondition",
"TreeInventoryModificationHTAction",
"TreeInventoryModificationHTCondition",
"TreeInventoryModificationRemoveAction",
Expand Down Expand Up @@ -300,6 +301,7 @@
from fastfuels_sdk.client_library.models.tree_inventory_modification_condition import TreeInventoryModificationCondition as TreeInventoryModificationCondition
from fastfuels_sdk.client_library.models.tree_inventory_modification_dia_action import TreeInventoryModificationDIAAction as TreeInventoryModificationDIAAction
from fastfuels_sdk.client_library.models.tree_inventory_modification_dia_condition import TreeInventoryModificationDIACondition as TreeInventoryModificationDIACondition
from fastfuels_sdk.client_library.models.tree_inventory_modification_expression_condition import TreeInventoryModificationExpressionCondition as TreeInventoryModificationExpressionCondition
from fastfuels_sdk.client_library.models.tree_inventory_modification_ht_action import TreeInventoryModificationHTAction as TreeInventoryModificationHTAction
from fastfuels_sdk.client_library.models.tree_inventory_modification_ht_condition import TreeInventoryModificationHTCondition as TreeInventoryModificationHTCondition
from fastfuels_sdk.client_library.models.tree_inventory_modification_remove_action import TreeInventoryModificationRemoveAction as TreeInventoryModificationRemoveAction
Expand Down
6 changes: 3 additions & 3 deletions fastfuels_sdk/client_library/api/tree_inventory_api.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion fastfuels_sdk/client_library/api_spec.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions fastfuels_sdk/client_library/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
from fastfuels_sdk.client_library.models.tree_inventory_modification_condition import TreeInventoryModificationCondition
from fastfuels_sdk.client_library.models.tree_inventory_modification_dia_action import TreeInventoryModificationDIAAction
from fastfuels_sdk.client_library.models.tree_inventory_modification_dia_condition import TreeInventoryModificationDIACondition
from fastfuels_sdk.client_library.models.tree_inventory_modification_expression_condition import TreeInventoryModificationExpressionCondition
from fastfuels_sdk.client_library.models.tree_inventory_modification_ht_action import TreeInventoryModificationHTAction
from fastfuels_sdk.client_library.models.tree_inventory_modification_ht_condition import TreeInventoryModificationHTCondition
from fastfuels_sdk.client_library.models.tree_inventory_modification_remove_action import TreeInventoryModificationRemoveAction
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,45 +13,47 @@


from __future__ import annotations
from inspect import getfullargspec
import json
import pprint
import re # noqa: F401
from pydantic import BaseModel, ConfigDict, Field, StrictStr, ValidationError, field_validator
from typing import Any, List, Optional
from typing import Optional
from fastfuels_sdk.client_library.models.tree_inventory_modification_cr_action import TreeInventoryModificationCRAction
from fastfuels_sdk.client_library.models.tree_inventory_modification_dia_action import TreeInventoryModificationDIAAction
from fastfuels_sdk.client_library.models.tree_inventory_modification_ht_action import TreeInventoryModificationHTAction
from fastfuels_sdk.client_library.models.tree_inventory_modification_remove_action import TreeInventoryModificationRemoveAction
from fastfuels_sdk.client_library.models.tree_inventory_modification_spcd_action import TreeInventoryModificationSPCDAction
from pydantic import StrictStr, Field
from typing import Union, List, Set, Optional, Dict
from typing import Union, Any, List, Set, TYPE_CHECKING, Optional, Dict
from typing_extensions import Literal, Self
from pydantic import Field

TREEINVENTORYMODIFICATIONACTION_ONE_OF_SCHEMAS = ["TreeInventoryModificationCRAction", "TreeInventoryModificationDIAAction", "TreeInventoryModificationHTAction", "TreeInventoryModificationRemoveAction", "TreeInventoryModificationSPCDAction"]
TREEINVENTORYMODIFICATIONACTION_ANY_OF_SCHEMAS = ["TreeInventoryModificationCRAction", "TreeInventoryModificationDIAAction", "TreeInventoryModificationHTAction", "TreeInventoryModificationRemoveAction", "TreeInventoryModificationSPCDAction"]

class TreeInventoryModificationAction(BaseModel):
"""
The actions for the tree inventory modification.
Actions to apply to trees. Use modifier='remove' to remove trees.
"""

# data type: TreeInventoryModificationSPCDAction
oneof_schema_1_validator: Optional[TreeInventoryModificationSPCDAction] = None
anyof_schema_1_validator: Optional[TreeInventoryModificationSPCDAction] = None
# data type: TreeInventoryModificationHTAction
oneof_schema_2_validator: Optional[TreeInventoryModificationHTAction] = None
anyof_schema_2_validator: Optional[TreeInventoryModificationHTAction] = None
# data type: TreeInventoryModificationDIAAction
oneof_schema_3_validator: Optional[TreeInventoryModificationDIAAction] = None
anyof_schema_3_validator: Optional[TreeInventoryModificationDIAAction] = None
# data type: TreeInventoryModificationCRAction
oneof_schema_4_validator: Optional[TreeInventoryModificationCRAction] = None
anyof_schema_4_validator: Optional[TreeInventoryModificationCRAction] = None
# data type: TreeInventoryModificationRemoveAction
oneof_schema_5_validator: Optional[TreeInventoryModificationRemoveAction] = None
actual_instance: Optional[Union[TreeInventoryModificationCRAction, TreeInventoryModificationDIAAction, TreeInventoryModificationHTAction, TreeInventoryModificationRemoveAction, TreeInventoryModificationSPCDAction]] = None
one_of_schemas: Set[str] = { "TreeInventoryModificationCRAction", "TreeInventoryModificationDIAAction", "TreeInventoryModificationHTAction", "TreeInventoryModificationRemoveAction", "TreeInventoryModificationSPCDAction" }

model_config = ConfigDict(
validate_assignment=True,
protected_namespaces=(),
)


discriminator_value_class_map: Dict[str, str] = {
anyof_schema_5_validator: Optional[TreeInventoryModificationRemoveAction] = None
if TYPE_CHECKING:
actual_instance: Optional[Union[TreeInventoryModificationCRAction, TreeInventoryModificationDIAAction, TreeInventoryModificationHTAction, TreeInventoryModificationRemoveAction, TreeInventoryModificationSPCDAction]] = None
else:
actual_instance: Any = None
any_of_schemas: Set[str] = { "TreeInventoryModificationCRAction", "TreeInventoryModificationDIAAction", "TreeInventoryModificationHTAction", "TreeInventoryModificationRemoveAction", "TreeInventoryModificationSPCDAction" }

model_config = {
"validate_assignment": True,
"protected_namespaces": (),
}

def __init__(self, *args, **kwargs) -> None:
Expand All @@ -65,92 +67,88 @@ def __init__(self, *args, **kwargs) -> None:
super().__init__(**kwargs)

@field_validator('actual_instance')
def actual_instance_must_validate_oneof(cls, v):
def actual_instance_must_validate_anyof(cls, v):
instance = TreeInventoryModificationAction.model_construct()
error_messages = []
match = 0
# validate data type: TreeInventoryModificationSPCDAction
if not isinstance(v, TreeInventoryModificationSPCDAction):
error_messages.append(f"Error! Input type `{type(v)}` is not `TreeInventoryModificationSPCDAction`")
else:
match += 1
return v

# validate data type: TreeInventoryModificationHTAction
if not isinstance(v, TreeInventoryModificationHTAction):
error_messages.append(f"Error! Input type `{type(v)}` is not `TreeInventoryModificationHTAction`")
else:
match += 1
return v

# validate data type: TreeInventoryModificationDIAAction
if not isinstance(v, TreeInventoryModificationDIAAction):
error_messages.append(f"Error! Input type `{type(v)}` is not `TreeInventoryModificationDIAAction`")
else:
match += 1
return v

# validate data type: TreeInventoryModificationCRAction
if not isinstance(v, TreeInventoryModificationCRAction):
error_messages.append(f"Error! Input type `{type(v)}` is not `TreeInventoryModificationCRAction`")
else:
match += 1
return v

# validate data type: TreeInventoryModificationRemoveAction
if not isinstance(v, TreeInventoryModificationRemoveAction):
error_messages.append(f"Error! Input type `{type(v)}` is not `TreeInventoryModificationRemoveAction`")
else:
match += 1
if match > 1:
# more than 1 match
raise ValueError("Multiple matches found when setting `actual_instance` in TreeInventoryModificationAction with oneOf schemas: TreeInventoryModificationCRAction, TreeInventoryModificationDIAAction, TreeInventoryModificationHTAction, TreeInventoryModificationRemoveAction, TreeInventoryModificationSPCDAction. Details: " + ", ".join(error_messages))
elif match == 0:
return v

if error_messages:
# no match
raise ValueError("No match found when setting `actual_instance` in TreeInventoryModificationAction with oneOf schemas: TreeInventoryModificationCRAction, TreeInventoryModificationDIAAction, TreeInventoryModificationHTAction, TreeInventoryModificationRemoveAction, TreeInventoryModificationSPCDAction. Details: " + ", ".join(error_messages))
raise ValueError("No match found when setting the actual_instance in TreeInventoryModificationAction with anyOf schemas: TreeInventoryModificationCRAction, TreeInventoryModificationDIAAction, TreeInventoryModificationHTAction, TreeInventoryModificationRemoveAction, TreeInventoryModificationSPCDAction. Details: " + ", ".join(error_messages))
else:
return v

@classmethod
def from_dict(cls, obj: Union[str, Dict[str, Any]]) -> Self:
def from_dict(cls, obj: Dict[str, Any]) -> Self:
return cls.from_json(json.dumps(obj))

@classmethod
def from_json(cls, json_str: str) -> Self:
"""Returns the object represented by the json string"""
instance = cls.model_construct()
error_messages = []
match = 0

# deserialize data into TreeInventoryModificationSPCDAction
# anyof_schema_1_validator: Optional[TreeInventoryModificationSPCDAction] = None
try:
instance.actual_instance = TreeInventoryModificationSPCDAction.from_json(json_str)
match += 1
return instance
except (ValidationError, ValueError) as e:
error_messages.append(str(e))
# deserialize data into TreeInventoryModificationHTAction
error_messages.append(str(e))
# anyof_schema_2_validator: Optional[TreeInventoryModificationHTAction] = None
try:
instance.actual_instance = TreeInventoryModificationHTAction.from_json(json_str)
match += 1
return instance
except (ValidationError, ValueError) as e:
error_messages.append(str(e))
# deserialize data into TreeInventoryModificationDIAAction
error_messages.append(str(e))
# anyof_schema_3_validator: Optional[TreeInventoryModificationDIAAction] = None
try:
instance.actual_instance = TreeInventoryModificationDIAAction.from_json(json_str)
match += 1
return instance
except (ValidationError, ValueError) as e:
error_messages.append(str(e))
# deserialize data into TreeInventoryModificationCRAction
error_messages.append(str(e))
# anyof_schema_4_validator: Optional[TreeInventoryModificationCRAction] = None
try:
instance.actual_instance = TreeInventoryModificationCRAction.from_json(json_str)
match += 1
return instance
except (ValidationError, ValueError) as e:
error_messages.append(str(e))
# deserialize data into TreeInventoryModificationRemoveAction
error_messages.append(str(e))
# anyof_schema_5_validator: Optional[TreeInventoryModificationRemoveAction] = None
try:
instance.actual_instance = TreeInventoryModificationRemoveAction.from_json(json_str)
match += 1
return instance
except (ValidationError, ValueError) as e:
error_messages.append(str(e))
error_messages.append(str(e))

if match > 1:
# more than 1 match
raise ValueError("Multiple matches found when deserializing the JSON string into TreeInventoryModificationAction with oneOf schemas: TreeInventoryModificationCRAction, TreeInventoryModificationDIAAction, TreeInventoryModificationHTAction, TreeInventoryModificationRemoveAction, TreeInventoryModificationSPCDAction. Details: " + ", ".join(error_messages))
elif match == 0:
if error_messages:
# no match
raise ValueError("No match found when deserializing the JSON string into TreeInventoryModificationAction with oneOf schemas: TreeInventoryModificationCRAction, TreeInventoryModificationDIAAction, TreeInventoryModificationHTAction, TreeInventoryModificationRemoveAction, TreeInventoryModificationSPCDAction. Details: " + ", ".join(error_messages))
raise ValueError("No match found when deserializing the JSON string into TreeInventoryModificationAction with anyOf schemas: TreeInventoryModificationCRAction, TreeInventoryModificationDIAAction, TreeInventoryModificationHTAction, TreeInventoryModificationRemoveAction, TreeInventoryModificationSPCDAction. Details: " + ", ".join(error_messages))
else:
return instance

Expand All @@ -172,7 +170,6 @@ def to_dict(self) -> Optional[Union[Dict[str, Any], TreeInventoryModificationCRA
if hasattr(self.actual_instance, "to_dict") and callable(self.actual_instance.to_dict):
return self.actual_instance.to_dict()
else:
# primitive type
return self.actual_instance

def to_str(self) -> str:
Expand Down
Loading
Loading