Skip to content

Commit 5fc3c70

Browse files
committed
add arrayName, type, numComponents to variable state
1 parent 056a5bc commit 5fc3c70

5 files changed

Lines changed: 90 additions & 2 deletions

File tree

‎src/ansys/visor/viewer/models/common/visor_variable_state.py‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
from typing import List, Tuple
44

5-
from pydantic import BaseModel, ConfigDict, Field
5+
from pydantic import BaseModel, ConfigDict, Field, field_serializer
6+
7+
from ansys.visor.viewer.core.visor_enums import VisorVtkVariableType
68

79

810
class VisorVariableState(BaseModel):
@@ -15,11 +17,24 @@ class VisorVariableState(BaseModel):
1517
a unique identifier for the variable: the variable name, type (POINT/CELL), and number of components, and computes
1618
the ranges across all datasets/parts that contain that variable.
1719
20+
``array_name``, ``type`` and ``num_components`` are those same three identifying properties, carried
21+
explicitly (rather than only opaquely inside ``id``) so a consumer can act on them without parsing the
22+
client-built identifier. They are required: a variable state with no known source array, association, or
23+
component count is not a state this model can represent.
24+
1825
In the future, the backend can own this, but for now we can treat this as passthrough data,
1926
as the id value is stable across sessions.
2027
"""
2128
model_config = ConfigDict(populate_by_name=True)
2229

2330
id: str = Field(...)
31+
array_name: str = Field(..., alias="arrayName")
32+
type: VisorVtkVariableType = Field(...)
33+
num_components: int = Field(..., alias="numComponents")
2434
magnitude_range: Tuple[float, float] | None = Field(default=None, alias="magnitudeRange")
2535
ranges: List[Tuple[float, float]] = Field(default_factory=list)
36+
37+
@field_serializer("type")
38+
def _serialize_type(self, value: VisorVtkVariableType) -> str:
39+
"""Emit the wire value (e.g. "POINT"/"CELL") for both dict-mode and JSON-mode dumps."""
40+
return value.value

‎src/ansys/visor/viewer/models/persist/persisted_viewer_state.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class PersistedViewerStateV1(BaseModel):
2525
"""
2626
model_config = ConfigDict(arbitrary_types_allowed=True)
2727

28-
version: Literal["1.0"] = Field(default="1.0")
28+
version: Literal["1.1"] = Field(default="1.1")
2929

3030
ui: VisorUIState = Field(default_factory=VisorUIState)
3131
scene: PersistedSceneState = Field(default_factory=PersistedSceneState)

‎src/ansys/visor/visor-client/src/VisorFrontend.tsx‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ export class VisorFrontend {
260260
for (const spectrumInfo of spectrumInfos.array) {
261261
const spectrumState = new VisorSpectrumState();
262262
spectrumState.setId(spectrumInfo.id.toString());
263+
spectrumState.setArrayName(spectrumInfo.name);
264+
spectrumState.setType(spectrumInfo.type);
265+
spectrumState.setNumComponents(spectrumInfo.numComponents);
263266
const magnitudeRange = spectrumInfo.getRangeInfo(-1);
264267
if (magnitudeRange == null) {
265268
throw new Error(`range at component ${-1} not found`);

‎src/ansys/visor/visor-client/src/state/appstate/VisorSpectrumState.tsx‎

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,19 @@
11
import {
22
ensureArray,
33
ensureNumberArray,
4+
ensureNumber,
5+
ensureString,
46
JsonDict,
57
parseState,
68
StateInput,
79
} from './VisorStateCommon.tsx';
10+
import type { FieldAssociation } from './vtkInfo/VisorVtkDataArray.tsx';
811

912
export default class VisorSpectrumState {
1013
private _id: string = '';
14+
private _arrayName: string = '';
15+
private _type: FieldAssociation | undefined = undefined;
16+
private _numComponents: number = 0;
1117
private _magnitudeRange: number[] | undefined = undefined;
1218
private _ranges: (number[] | undefined)[] = [];
1319

@@ -28,6 +34,36 @@ export default class VisorSpectrumState {
2834
}
2935
}
3036

37+
get arrayName(): string {
38+
return this._arrayName;
39+
}
40+
41+
setArrayName(val: string | null | undefined): void {
42+
if (val != null) {
43+
this._arrayName = ensureString(val, 'val');
44+
}
45+
}
46+
47+
get type(): FieldAssociation | undefined {
48+
return this._type;
49+
}
50+
51+
setType(val: FieldAssociation | null | undefined): void {
52+
if (val != null) {
53+
this._type = val;
54+
}
55+
}
56+
57+
get numComponents(): number {
58+
return this._numComponents;
59+
}
60+
61+
setNumComponents(val: number | null | undefined): void {
62+
if (val != null) {
63+
this._numComponents = ensureNumber(val, 'val');
64+
}
65+
}
66+
3167
get magnitudeRange(): number[] | undefined {
3268
return this._magnitudeRange;
3369
}
@@ -83,6 +119,11 @@ export default class VisorSpectrumState {
83119
}
84120

85121
this.setId(thisId);
122+
this.setArrayName(data.arrayName === undefined ? this._arrayName : data.arrayName);
123+
this.setType(data.type === undefined ? this._type : data.type);
124+
this.setNumComponents(
125+
data.numComponents === undefined ? this._numComponents : data.numComponents
126+
);
86127
this.setMagnitudeRange(
87128
data.magnitudeRange === undefined ? this._magnitudeRange : data.magnitudeRange,
88129
replace
@@ -99,6 +140,9 @@ export default class VisorSpectrumState {
99140
toDict(): JsonDict {
100141
return {
101142
id: this.id,
143+
arrayName: this.arrayName,
144+
type: this.type,
145+
numComponents: this.numComponents,
102146
magnitudeRange: this.magnitudeRange,
103147
ranges: this.ranges,
104148
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Unit tests for VisorVariableState."""
2+
3+
import pytest
4+
from pydantic import ValidationError
5+
6+
from ansys.visor.viewer.core.visor_enums import VisorVtkVariableType
7+
from ansys.visor.viewer.models.common.visor_variable_state import VisorVariableState
8+
9+
_VALID_KWARGS = {
10+
"id": "POINT::displacement::3",
11+
"array_name": "displacement",
12+
"type": VisorVtkVariableType.POINT,
13+
"num_components": 3,
14+
}
15+
16+
17+
@pytest.mark.parametrize("missing_field", ["array_name", "type", "num_components"])
18+
def test_construction_missing_required_field_raises(missing_field):
19+
"""Omitting any one of array_name, type, or num_components must raise,
20+
proving each is required on its own rather than all three being
21+
collectively-but-not-individually required."""
22+
kwargs = {k: v for k, v in _VALID_KWARGS.items() if k != missing_field}
23+
24+
with pytest.raises(ValidationError):
25+
VisorVariableState(**kwargs)
26+

0 commit comments

Comments
 (0)