Skip to content

Commit 610ea8a

Browse files
authored
Merge pull request #170 from MiraGeoscience/GEOPY-2004
GEOPY-2004: Draft a uml file for the UIJson/Params design
2 parents 077d40e + 44d0405 commit 610ea8a

2 files changed

Lines changed: 184 additions & 0 deletions

File tree

tests/uijson_test.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,42 @@ def test_gravity_uijson(tmp_path):
113113
params_data_nobraces[param] = field_data_nobraces
114114

115115
assert uijson_data == params_data_nobraces
116+
117+
118+
def test_field_handling():
119+
# TODO: This is was for prototyping and should be removed once the
120+
# behaviours tested here are incorporated into the UIJson classes.
121+
122+
import warnings
123+
from typing import Annotated, Any
124+
125+
from pydantic import AliasChoices, BaseModel, BeforeValidator, Field
126+
127+
def deprecate(value, info):
128+
warnings.warn( # will be a logging.warn in production
129+
f"Field {info.field_name} is deprecated."
130+
)
131+
return value
132+
133+
Deprecated = Annotated[
134+
Any,
135+
Field(exclude=True),
136+
BeforeValidator(deprecate),
137+
]
138+
139+
class MyClass(BaseModel):
140+
a: int = 1 # Represents a newly added field with a default value.
141+
b: int = Field( # Represents a field with a name change.
142+
validation_alias=AliasChoices("b", "bb")
143+
)
144+
c: Deprecated # Represents a deprecated field.
145+
146+
test = MyClass(bb=2, c=3)
147+
assert test.a == 1
148+
assert test.b == 2
149+
150+
dump = test.model_dump()
151+
assert "c" not in dump
152+
assert "b" in dump
153+
assert "bb" not in dump
154+
assert dump["a"] == 1

uml/classes_uijson.puml

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
@startuml classes_uijson
2+
set namespaceSeparator none
3+
4+
class GravityInversionUIJson {
5+
active_model : DataForm
6+
alpha_s : DataForm
7+
auto_scale_misfits : BoolForm
8+
beta_tol : FloatForm
9+
chi_factor : FloatForm
10+
chunk_by_rows : BoolForm
11+
coolingFactor : FloatForm
12+
coolingRate : IntegerForm
13+
data_object : ObjectForm
14+
default_ui_json : ClassVar[Path]
15+
distributed_workers : str
16+
every_iteration_bool : BoolForm
17+
f_min_change : FloatForm
18+
forward_only : bool
19+
ga_group : str
20+
generate_sweep : BoolForm
21+
gradient_type : ChoiceForm
22+
guv_channel : DataForm
23+
guv_uncertainty : DataForm
24+
gx_channel : DataForm
25+
gx_uncertainty : DataForm
26+
gxx_channel : DataForm
27+
gxx_uncertainty : DataForm
28+
gxy_channel : DataForm
29+
gxy_uncertainty : DataForm
30+
gxz_channel : DataForm
31+
gxz_uncertainty : DataForm
32+
gy_channel : DataForm
33+
gy_uncertainty : DataForm
34+
gyy_channel : DataForm
35+
gyy_uncertainty : DataForm
36+
gyz_channel : DataForm
37+
gyz_uncertainty : DataForm
38+
gz_channel : DataForm
39+
gz_uncertainty : DataForm
40+
gzz_channel : DataForm
41+
gzz_uncertainty : DataForm
42+
initial_beta : FloatForm
43+
initial_beta_ratio : FloatForm
44+
inversion_style : Deprecated
45+
inversion_type : str
46+
length_scale_x : DataForm
47+
length_scale_y : DataForm
48+
length_scale_z : DataForm
49+
lower_bound : DataForm
50+
max_cg_iterations : IntegerForm
51+
max_chunk_size : IntegerForm
52+
max_global_iterations : IntegerForm
53+
max_irls_iterations : IntegerForm
54+
max_line_search_iterations : IntegerForm
55+
max_ram : str
56+
mesh : ObjectForm
57+
n_cpu : IntegerForm
58+
out_group : GroupForm
59+
output_tile_files : bool
60+
parallelized : BoolForm
61+
{field} percentile : Field(IntegerForm, validation_alias=AliasChoices("percentile", "prctile"))
62+
reference_model : DataForm
63+
s_norm : DataForm
64+
save_sensitivities : BoolForm
65+
sens_wts_threshold : FloatForm
66+
starting_chi_factor : FloatForm
67+
starting_model : DataForm
68+
store_sensitivities : ChoiceForm
69+
tile_spatial : DataForm
70+
tol_cg : FloatForm
71+
topography : DataForm
72+
topography_object : ObjectForm
73+
upper_bound : DataForm
74+
x_norm : DataForm
75+
y_norm : DataForm
76+
z_norm : DataForm
77+
validate_version()
78+
}
79+
note left of GravityInversionUIJson::inversion_style
80+
- inversion_style is an example of a deprecated field.
81+
- We can handle these with a special annotation.
82+
- The annotation accepts Any type, contains a Field with
83+
exclude=True set so that it is not written to the
84+
ui.json file, and it contains a BeforeValidator that
85+
logs a warning about the deprecation.
86+
- The annotation definition can be stored in geoh5py and
87+
imported and used wherever needed.
88+
end note
89+
90+
91+
note left of GravityInversionUIJson::prctile
92+
- percentile is an example of a parameter whose name has
93+
been updated.
94+
- We can handle these with a validation_alias.
95+
- This will accept old naming conventions, while writing
96+
the new naming convention to file at the end of the run.
97+
end note
98+
99+
note left of GravityInversionUIJson::validate_version
100+
- logs a warning about provided uijson version not
101+
matching the current simpeg_drivers.__version__
102+
- returns the current version since the uijson will
103+
be written without any deprecated fields and will
104+
add any newer parameters that have default values
105+
end note
106+
107+
108+
class GravityDriver {
109+
ui_json_class : ClassVar[GravityInversionUIJson]
110+
options_class : ClassVar[GravityInversionOptions]
111+
uijson: GravityInversionUIJson
112+
options : GravityInversionOptions
113+
GravityDriver from_uijson(GravityInversionUIJson)
114+
GravityDriver from_options(GravityInversionOptions)
115+
@classmethod start(Path)
116+
}
117+
note left of GravityDriver::options
118+
- options is a property that constructs only once.
119+
- returns self.options_class(**self.ui_json.to_params()).
120+
- options is then passes around the factories to assemble
121+
inversion components.
122+
end note
123+
124+
note left of GravityDriver::uijson
125+
- uijson is a stored on creation, and is frozen to modification.
126+
- if data is modified during the run, such as what happens when
127+
we copy objects into the out_group, the driver can model dump,
128+
update the data, then construct a new UIJson instance to write
129+
the ui.json file that stores the data used in the run.
130+
end note
131+
132+
note left of GravityDriver::start
133+
- reads plain json
134+
- infers forward_only and inversion_type to select driver import
135+
- use inversion_type and forward_only to import driver using
136+
cls.driver_class_from_name()
137+
- retrieve ui_json_class from driver and instantiate from json.load output
138+
- instantiate driver with UIJson instance (init stores UIJson instance)
139+
and return the driver instance
140+
end note
141+
142+
GravityDriver o-- GravityInversionUIJson
143+
144+
145+
@enduml

0 commit comments

Comments
 (0)