pyfemtet 1.0.5__py3-none-any.whl → 1.0.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyfemtet might be problematic. Click here for more details.
- pyfemtet/opt/femopt.py +9 -0
- pyfemtet/opt/history/_history.py +58 -7
- pyfemtet/opt/optimizer/_base_optimizer.py +51 -8
- pyfemtet/opt/problem/problem.py +9 -0
- pyfemtet/opt/problem/variable_manager/_variable_manager.py +1 -1
- pyfemtet/opt/visualization/history_viewer/_complex_components/detail_graphs.py +556 -0
- pyfemtet/opt/visualization/history_viewer/_detail_page.py +106 -0
- pyfemtet/opt/visualization/history_viewer/_process_monitor/_application.py +3 -2
- pyfemtet/opt/visualization/history_viewer/result_viewer/_application.py +3 -2
- pyfemtet/opt/visualization/history_viewer/result_viewer/_pages.py +1 -0
- pyfemtet/opt/visualization/plotter/contour_creator.py +105 -0
- pyfemtet/opt/visualization/plotter/parallel_plot_creator.py +33 -0
- pyfemtet/opt/visualization/plotter/pm_graph_creator.py +7 -7
- {pyfemtet-1.0.5.dist-info → pyfemtet-1.0.7.dist-info}/METADATA +1 -1
- {pyfemtet-1.0.5.dist-info → pyfemtet-1.0.7.dist-info}/RECORD +19 -15
- {pyfemtet-1.0.5.dist-info → pyfemtet-1.0.7.dist-info}/LICENSE +0 -0
- {pyfemtet-1.0.5.dist-info → pyfemtet-1.0.7.dist-info}/LICENSE_THIRD_PARTY.txt +0 -0
- {pyfemtet-1.0.5.dist-info → pyfemtet-1.0.7.dist-info}/WHEEL +0 -0
- {pyfemtet-1.0.5.dist-info → pyfemtet-1.0.7.dist-info}/entry_points.txt +0 -0
pyfemtet/opt/femopt.py
CHANGED
|
@@ -157,6 +157,15 @@ class FEMOpt:
|
|
|
157
157
|
):
|
|
158
158
|
self.opt.add_constraint(name, fun, lower_bound, upper_bound, args, kwargs, strict, using_fem)
|
|
159
159
|
|
|
160
|
+
def add_other_output(
|
|
161
|
+
self,
|
|
162
|
+
name: str,
|
|
163
|
+
fun: Callable[..., float],
|
|
164
|
+
args: tuple | None = None,
|
|
165
|
+
kwargs: dict | None = None,
|
|
166
|
+
):
|
|
167
|
+
self.opt.add_other_output(name, fun, args, kwargs)
|
|
168
|
+
|
|
160
169
|
def add_sub_fidelity_model(
|
|
161
170
|
self,
|
|
162
171
|
name: str,
|
pyfemtet/opt/history/_history.py
CHANGED
|
@@ -326,6 +326,7 @@ class ColumnManager:
|
|
|
326
326
|
parameters: TrialInput
|
|
327
327
|
y_names: list[str]
|
|
328
328
|
c_names: list[str]
|
|
329
|
+
other_output_names: list[str]
|
|
329
330
|
column_dtypes: dict[str, type]
|
|
330
331
|
meta_columns: list[str]
|
|
331
332
|
|
|
@@ -340,12 +341,14 @@ class ColumnManager:
|
|
|
340
341
|
parameters: TrialInput,
|
|
341
342
|
y_names,
|
|
342
343
|
c_names,
|
|
344
|
+
other_output_names,
|
|
343
345
|
additional_data: dict,
|
|
344
346
|
column_order_mode: str = ColumnOrderMode.per_category,
|
|
345
347
|
):
|
|
346
348
|
self.parameters = parameters
|
|
347
349
|
self.y_names = y_names
|
|
348
350
|
self.c_names = c_names
|
|
351
|
+
self.other_output_names=other_output_names
|
|
349
352
|
self.set_full_sorted_column_information(
|
|
350
353
|
additional_data=additional_data,
|
|
351
354
|
column_order_mode=column_order_mode,
|
|
@@ -356,12 +359,14 @@ class ColumnManager:
|
|
|
356
359
|
extra_parameters: TrialInput = None,
|
|
357
360
|
extra_y_names: list[str] = None,
|
|
358
361
|
extra_c_names: list[str] = None,
|
|
362
|
+
extra_other_output_names: list[str] = None,
|
|
359
363
|
additional_data: dict = None,
|
|
360
364
|
column_order_mode: str = ColumnOrderMode.per_category,
|
|
361
365
|
):
|
|
362
366
|
extra_parameters = extra_parameters or TrialInput()
|
|
363
367
|
extra_y_names = extra_y_names or []
|
|
364
368
|
extra_c_names = extra_c_names or []
|
|
369
|
+
extra_other_output_names = extra_other_output_names or []
|
|
365
370
|
|
|
366
371
|
# column name になるので重複は許されない
|
|
367
372
|
column_dtypes: dict = NoDuplicateDict()
|
|
@@ -503,6 +508,17 @@ class ColumnManager:
|
|
|
503
508
|
target_cds.update({f_ub(name): float})
|
|
504
509
|
target_mcs.append('')
|
|
505
510
|
|
|
511
|
+
elif key == 'other_outputs':
|
|
512
|
+
for name in self.other_output_names:
|
|
513
|
+
# important
|
|
514
|
+
column_dtypes.update({name: float})
|
|
515
|
+
meta_columns.append('other_output.value')
|
|
516
|
+
|
|
517
|
+
for name in extra_other_output_names:
|
|
518
|
+
# later
|
|
519
|
+
target_cds.update({name: float})
|
|
520
|
+
target_mcs.append('')
|
|
521
|
+
|
|
506
522
|
# additional_data を入れる
|
|
507
523
|
elif key == self._get_additional_data_column():
|
|
508
524
|
# important
|
|
@@ -578,6 +594,9 @@ class ColumnManager:
|
|
|
578
594
|
def get_cns_names(self) -> list[str]:
|
|
579
595
|
return self.filter_columns('cns')
|
|
580
596
|
|
|
597
|
+
def get_other_output_names(self) -> list[str]:
|
|
598
|
+
return self.filter_columns('other_output')
|
|
599
|
+
|
|
581
600
|
@staticmethod
|
|
582
601
|
def _is_numerical_parameter(prm_name, columns):
|
|
583
602
|
prm_lb_name = CorrespondingColumnNameRuler.prm_lower_bound_name(prm_name)
|
|
@@ -672,6 +691,7 @@ class Record:
|
|
|
672
691
|
x: TrialInput = dataclasses.field(default_factory=TrialInput)
|
|
673
692
|
y: TrialOutput = dataclasses.field(default_factory=TrialOutput)
|
|
674
693
|
c: TrialConstraintOutput = dataclasses.field(default_factory=TrialConstraintOutput)
|
|
694
|
+
other_outputs: TrialFunctionOutput = dataclasses.field(default_factory=TrialFunctionOutput)
|
|
675
695
|
state: TrialState = TrialState.undefined
|
|
676
696
|
datetime_start: datetime.datetime = dataclasses.field(default_factory=datetime.datetime.now)
|
|
677
697
|
datetime_end: datetime.datetime = dataclasses.field(default_factory=datetime.datetime.now)
|
|
@@ -689,6 +709,7 @@ class Record:
|
|
|
689
709
|
x: TrialInput = d.pop('x')
|
|
690
710
|
y: TrialOutput = d.pop('y')
|
|
691
711
|
c: TrialConstraintOutput = d.pop('c')
|
|
712
|
+
other_outputs: TrialFunctionOutput = d.pop('other_outputs')
|
|
692
713
|
|
|
693
714
|
# prm
|
|
694
715
|
for prm_name, param in x.items():
|
|
@@ -723,6 +744,9 @@ class Record:
|
|
|
723
744
|
d.update(**{f'{f_ub(k)}': v.upper_bound
|
|
724
745
|
for k, v in c.items()})
|
|
725
746
|
|
|
747
|
+
# function
|
|
748
|
+
d.update(**{k: v.value for k, v in other_outputs.items()})
|
|
749
|
+
|
|
726
750
|
df = pd.DataFrame(
|
|
727
751
|
{k: [v] for k, v in d.items()},
|
|
728
752
|
columns=tuple(dtypes.keys())
|
|
@@ -917,11 +941,13 @@ class Records:
|
|
|
917
941
|
loaded_prm_names = set(self.column_manager._filter_prm_names(loaded_columns, loaded_meta_columns))
|
|
918
942
|
loaded_obj_names = set(self.column_manager._filter_columns('obj', loaded_columns, loaded_meta_columns))
|
|
919
943
|
loaded_cns_names = set(self.column_manager._filter_columns('cns', loaded_columns, loaded_meta_columns))
|
|
944
|
+
loaded_other_output_names = set(self.column_manager._filter_columns('other_output.value', loaded_columns, loaded_meta_columns))
|
|
920
945
|
|
|
921
946
|
# loaded df に存在するが Record に存在しないカラムを Record に追加
|
|
922
947
|
extra_parameters = {}
|
|
923
948
|
extra_y_names = []
|
|
924
949
|
extra_c_names = []
|
|
950
|
+
extra_oo_names = []
|
|
925
951
|
for l_col, l_meta in zip(loaded_columns, loaded_meta_columns):
|
|
926
952
|
|
|
927
953
|
# 現在の Record に含まれないならば
|
|
@@ -958,6 +984,10 @@ class Records:
|
|
|
958
984
|
elif l_col in loaded_cns_names:
|
|
959
985
|
extra_c_names.append(l_col)
|
|
960
986
|
|
|
987
|
+
# other_output_name ならば
|
|
988
|
+
elif l_col in loaded_other_output_names:
|
|
989
|
+
extra_oo_names.append(l_col)
|
|
990
|
+
|
|
961
991
|
# additional data を取得
|
|
962
992
|
a_data = self.column_manager._get_additional_data(loaded_columns, loaded_meta_columns)
|
|
963
993
|
|
|
@@ -965,6 +995,7 @@ class Records:
|
|
|
965
995
|
extra_parameters=extra_parameters,
|
|
966
996
|
extra_y_names=extra_y_names,
|
|
967
997
|
extra_c_names=extra_c_names,
|
|
998
|
+
extra_other_output_names=extra_oo_names,
|
|
968
999
|
additional_data=a_data,
|
|
969
1000
|
column_order_mode=column_order_mode,
|
|
970
1001
|
)
|
|
@@ -1139,6 +1170,7 @@ class History:
|
|
|
1139
1170
|
prm_names: list[str]
|
|
1140
1171
|
obj_names: list[str]
|
|
1141
1172
|
cns_names: list[str]
|
|
1173
|
+
other_output_names: list[str]
|
|
1142
1174
|
sub_fidelity_names: list[str]
|
|
1143
1175
|
is_restart: bool
|
|
1144
1176
|
additional_data: dict
|
|
@@ -1151,6 +1183,10 @@ class History:
|
|
|
1151
1183
|
when the optimization process starts.
|
|
1152
1184
|
"""
|
|
1153
1185
|
|
|
1186
|
+
@property
|
|
1187
|
+
def all_output_names(self) -> list[str]:
|
|
1188
|
+
return self.obj_names + self.cns_names + self.other_output_names
|
|
1189
|
+
|
|
1154
1190
|
def __init__(self):
|
|
1155
1191
|
self._records = Records()
|
|
1156
1192
|
self.path: str | None = None
|
|
@@ -1189,6 +1225,7 @@ class History:
|
|
|
1189
1225
|
self.prm_names = ColumnManager._filter_prm_names(df.columns, meta_columns)
|
|
1190
1226
|
self.obj_names = ColumnManager._filter_columns('obj', df.columns, meta_columns)
|
|
1191
1227
|
self.cns_names = ColumnManager._filter_columns('cns', df.columns, meta_columns)
|
|
1228
|
+
self.other_output_names = ColumnManager._filter_columns('other_output.value', df.columns, meta_columns)
|
|
1192
1229
|
self.sub_fidelity_names = ColumnManager._get_sub_fidelity_names(df)
|
|
1193
1230
|
self.additional_data = ColumnManager._get_additional_data(df.columns, meta_columns)
|
|
1194
1231
|
|
|
@@ -1201,6 +1238,7 @@ class History:
|
|
|
1201
1238
|
parameters,
|
|
1202
1239
|
self.obj_names,
|
|
1203
1240
|
self.cns_names,
|
|
1241
|
+
self.other_output_names,
|
|
1204
1242
|
self.sub_fidelity_names,
|
|
1205
1243
|
self.additional_data,
|
|
1206
1244
|
)
|
|
@@ -1210,6 +1248,7 @@ class History:
|
|
|
1210
1248
|
parameters: TrialInput,
|
|
1211
1249
|
obj_names,
|
|
1212
1250
|
cns_names,
|
|
1251
|
+
other_output_names,
|
|
1213
1252
|
sub_fidelity_names,
|
|
1214
1253
|
additional_data,
|
|
1215
1254
|
):
|
|
@@ -1218,13 +1257,15 @@ class History:
|
|
|
1218
1257
|
self.prm_names = list(parameters.keys())
|
|
1219
1258
|
self.obj_names = list(obj_names)
|
|
1220
1259
|
self.cns_names = list(cns_names)
|
|
1260
|
+
self.other_output_names = list(other_output_names)
|
|
1221
1261
|
self.sub_fidelity_names = list(sub_fidelity_names)
|
|
1222
1262
|
self.additional_data.update(additional_data)
|
|
1223
1263
|
|
|
1224
1264
|
if not self._finalized:
|
|
1225
1265
|
# ここで column_dtypes が決定する
|
|
1226
1266
|
self._records.column_manager.initialize(
|
|
1227
|
-
parameters, self.obj_names, self.cns_names, self.
|
|
1267
|
+
parameters, self.obj_names, self.cns_names, self.other_output_names,
|
|
1268
|
+
self.additional_data, self.column_order_mode
|
|
1228
1269
|
)
|
|
1229
1270
|
|
|
1230
1271
|
# initialize
|
|
@@ -1381,6 +1422,8 @@ class History:
|
|
|
1381
1422
|
self._records.save(self.path)
|
|
1382
1423
|
|
|
1383
1424
|
def _create_optuna_study_for_visualization(self):
|
|
1425
|
+
"""出力は internal ではない値で、objective は出力という意味であり cns, other_output を含む。"""
|
|
1426
|
+
|
|
1384
1427
|
import optuna
|
|
1385
1428
|
|
|
1386
1429
|
# create study
|
|
@@ -1388,10 +1431,10 @@ class History:
|
|
|
1388
1431
|
# storage='sqlite:///' + os.path.basename(self.path) + '_dummy.db',
|
|
1389
1432
|
sampler=None, pruner=None, study_name='dummy',
|
|
1390
1433
|
)
|
|
1391
|
-
if len(self.
|
|
1434
|
+
if len(self.all_output_names) == 1:
|
|
1392
1435
|
kwargs.update(dict(direction='minimize'))
|
|
1393
1436
|
else:
|
|
1394
|
-
kwargs.update(dict(directions=['minimize']*len(self.
|
|
1437
|
+
kwargs.update(dict(directions=['minimize']*len(self.all_output_names)))
|
|
1395
1438
|
study = optuna.create_study(**kwargs)
|
|
1396
1439
|
|
|
1397
1440
|
# add trial to study
|
|
@@ -1441,11 +1484,19 @@ class History:
|
|
|
1441
1484
|
)
|
|
1442
1485
|
trial_kwargs.update(dict(distributions=distributions))
|
|
1443
1486
|
|
|
1444
|
-
# objective
|
|
1445
|
-
if len(self.
|
|
1446
|
-
|
|
1487
|
+
# objective (+ constraints + other_outputs as objective)
|
|
1488
|
+
if len(self.all_output_names) == 1:
|
|
1489
|
+
if len(self.obj_names) == 1:
|
|
1490
|
+
trial_kwargs.update(dict(value=row[self.obj_names].values[0]))
|
|
1491
|
+
elif len(self.cns_names) == 1:
|
|
1492
|
+
trial_kwargs.update(dict(value=row[self.cns_names].values[0]))
|
|
1493
|
+
elif len(self.other_output_names) == 1:
|
|
1494
|
+
trial_kwargs.update(dict(value=row[self.other_output_names].values[0]))
|
|
1495
|
+
else:
|
|
1496
|
+
assert False
|
|
1447
1497
|
else:
|
|
1448
|
-
|
|
1498
|
+
values = row[self.all_output_names].values
|
|
1499
|
+
trial_kwargs.update(dict(values=values))
|
|
1449
1500
|
|
|
1450
1501
|
# add to study
|
|
1451
1502
|
trial = optuna.create_trial(**trial_kwargs)
|
|
@@ -99,6 +99,7 @@ class AbstractOptimizer:
|
|
|
99
99
|
self.variable_manager = VariableManager()
|
|
100
100
|
self.objectives = Objectives()
|
|
101
101
|
self.constraints = Constraints()
|
|
102
|
+
self.other_outputs = Functions()
|
|
102
103
|
|
|
103
104
|
# multi-fidelity
|
|
104
105
|
self.fidelity = None
|
|
@@ -339,6 +340,21 @@ class AbstractOptimizer:
|
|
|
339
340
|
_duplicated_name_check(name, self.constraints.keys())
|
|
340
341
|
self.constraints.update({name: cns})
|
|
341
342
|
|
|
343
|
+
def add_other_output(
|
|
344
|
+
self,
|
|
345
|
+
name: str,
|
|
346
|
+
fun: Callable[..., float],
|
|
347
|
+
args: tuple | None = None,
|
|
348
|
+
kwargs: dict | None = None,
|
|
349
|
+
):
|
|
350
|
+
|
|
351
|
+
other_func = Function()
|
|
352
|
+
other_func.fun = fun
|
|
353
|
+
other_func.args = args or ()
|
|
354
|
+
other_func.kwargs = kwargs or {}
|
|
355
|
+
_duplicated_name_check(name, self.other_outputs.keys())
|
|
356
|
+
self.other_outputs.update({name: other_func})
|
|
357
|
+
|
|
342
358
|
def add_sub_fidelity_model(
|
|
343
359
|
self,
|
|
344
360
|
name: str,
|
|
@@ -352,12 +368,12 @@ class AbstractOptimizer:
|
|
|
352
368
|
_duplicated_name_check(name, self.sub_fidelity_models.keys())
|
|
353
369
|
self.sub_fidelity_models._update(name, sub_fidelity_model, fidelity)
|
|
354
370
|
|
|
355
|
-
def get_variables(self, format='dict'):
|
|
371
|
+
def get_variables(self, format: Literal['dict', 'values', 'raw'] = 'dict'):
|
|
356
372
|
return self.variable_manager.get_variables(
|
|
357
373
|
format=format,
|
|
358
374
|
)
|
|
359
375
|
|
|
360
|
-
def get_parameter(self, format='dict'):
|
|
376
|
+
def get_parameter(self, format: Literal['dict', 'values', 'raw'] = 'dict'):
|
|
361
377
|
return self.variable_manager.get_variables(
|
|
362
378
|
format=format, filter='parameter'
|
|
363
379
|
)
|
|
@@ -399,6 +415,12 @@ class AbstractOptimizer:
|
|
|
399
415
|
out.update({name: cns_result})
|
|
400
416
|
return out
|
|
401
417
|
|
|
418
|
+
def _other_outputs(self, out: TrialFunctionOutput) -> TrialFunctionOutput:
|
|
419
|
+
for name, other_func in self.other_outputs.items():
|
|
420
|
+
other_func_result = FunctionResult(other_func, self.fem)
|
|
421
|
+
out.update({name: other_func_result})
|
|
422
|
+
return out
|
|
423
|
+
|
|
402
424
|
def _get_hard_constraint_violation_names(self, hard_c: TrialConstraintOutput) -> list[str]:
|
|
403
425
|
violation_names = []
|
|
404
426
|
for name, result in hard_c.items():
|
|
@@ -573,6 +595,7 @@ class AbstractOptimizer:
|
|
|
573
595
|
|
|
574
596
|
try:
|
|
575
597
|
y: TrialOutput = opt_._y()
|
|
598
|
+
record.y = y
|
|
576
599
|
opt_._check_and_raise_interruption()
|
|
577
600
|
|
|
578
601
|
# if intentional error (by user)
|
|
@@ -604,7 +627,6 @@ class AbstractOptimizer:
|
|
|
604
627
|
_c.update(soft_c)
|
|
605
628
|
_c.update(hard_c)
|
|
606
629
|
|
|
607
|
-
record.y = y
|
|
608
630
|
record.c = _c
|
|
609
631
|
record.state = TrialState.get_corresponding_state_from_exception(e)
|
|
610
632
|
record.messages.append(
|
|
@@ -619,12 +641,32 @@ class AbstractOptimizer:
|
|
|
619
641
|
c.update(soft_c)
|
|
620
642
|
c.update(hard_c)
|
|
621
643
|
|
|
644
|
+
# ===== evaluate other functions =====
|
|
645
|
+
logger.info(_('evaluating other functions...'))
|
|
646
|
+
|
|
647
|
+
other_outputs = TrialFunctionOutput()
|
|
648
|
+
try:
|
|
649
|
+
opt_._other_outputs(other_outputs)
|
|
650
|
+
record.other_outputs = other_outputs
|
|
651
|
+
|
|
652
|
+
# if intentional error (by user)
|
|
653
|
+
except _HiddenConstraintViolation as e:
|
|
654
|
+
_log_hidden_constraint(e)
|
|
655
|
+
|
|
656
|
+
record.other_outputs = other_outputs
|
|
657
|
+
record.state = TrialState.get_corresponding_state_from_exception(e)
|
|
658
|
+
record.messages.append(
|
|
659
|
+
_('Hidden constraint violation during '
|
|
660
|
+
'another output function evaluation: ')
|
|
661
|
+
+ create_err_msg_from_exception(e))
|
|
662
|
+
|
|
663
|
+
raise e
|
|
664
|
+
|
|
622
665
|
# get values as minimize
|
|
623
666
|
y_internal: dict = opt_._convert_y(y)
|
|
624
667
|
|
|
625
668
|
logger.info(_('output:'))
|
|
626
669
|
logger.info(y)
|
|
627
|
-
record.y = y
|
|
628
670
|
record.c = c
|
|
629
671
|
record.state = TrialState.succeeded
|
|
630
672
|
|
|
@@ -858,10 +900,11 @@ class AbstractOptimizer:
|
|
|
858
900
|
filter='parameter', format='raw'
|
|
859
901
|
)
|
|
860
902
|
self.history.finalize(
|
|
861
|
-
parameters,
|
|
862
|
-
list(self.objectives.keys()),
|
|
863
|
-
list(self.constraints.keys()),
|
|
864
|
-
|
|
903
|
+
parameters=parameters,
|
|
904
|
+
obj_names=list(self.objectives.keys()),
|
|
905
|
+
cns_names=list(self.constraints.keys()),
|
|
906
|
+
other_output_names=list(self.other_outputs.keys()),
|
|
907
|
+
sub_fidelity_names=[self.sub_fidelity_name] + list(self.sub_fidelity_models.keys()),
|
|
865
908
|
additional_data=self._collect_additional_data()
|
|
866
909
|
)
|
|
867
910
|
|
pyfemtet/opt/problem/problem.py
CHANGED
|
@@ -28,7 +28,9 @@ __all__ = [
|
|
|
28
28
|
'TrialInput',
|
|
29
29
|
'TrialOutput',
|
|
30
30
|
'TrialConstraintOutput',
|
|
31
|
+
'TrialFunctionOutput',
|
|
31
32
|
'Function',
|
|
33
|
+
'FunctionResult',
|
|
32
34
|
'Functions',
|
|
33
35
|
'Objective',
|
|
34
36
|
'ObjectiveResult',
|
|
@@ -138,6 +140,12 @@ class Objective(Function):
|
|
|
138
140
|
return self._convert(value, self.direction)
|
|
139
141
|
|
|
140
142
|
|
|
143
|
+
class FunctionResult:
|
|
144
|
+
|
|
145
|
+
def __init__(self, func: Function, fem: AbstractFEMInterface):
|
|
146
|
+
self.value: float = func.eval(fem)
|
|
147
|
+
|
|
148
|
+
|
|
141
149
|
class ObjectiveResult:
|
|
142
150
|
|
|
143
151
|
def __init__(self, obj: Objective, fem: AbstractFEMInterface, obj_value: float = None):
|
|
@@ -302,3 +310,4 @@ SubSampling: TypeAlias = int
|
|
|
302
310
|
TrialInput: TypeAlias = dict[str, Variable]
|
|
303
311
|
TrialOutput: TypeAlias = dict[str, ObjectiveResult]
|
|
304
312
|
TrialConstraintOutput: TypeAlias = dict[str, ConstraintResult]
|
|
313
|
+
TrialFunctionOutput: TypeAlias = dict[str, FunctionResult]
|
|
@@ -304,7 +304,7 @@ class VariableManager:
|
|
|
304
304
|
filter: (Literal['pass_to_fem', 'parameter']
|
|
305
305
|
| tuple[Literal['pass_to_fem', 'parameter']]
|
|
306
306
|
| None) = None, # 'pass_to_fem' and 'parameter' (OR filter)
|
|
307
|
-
format:
|
|
307
|
+
format: Literal['dict', 'values', 'raw'] | None = None, # Defaults to 'raw'
|
|
308
308
|
) -> (
|
|
309
309
|
dict[str, Variable]
|
|
310
310
|
| dict[str, Parameter]
|