amisc.system
The SystemSurrogate
is a framework for multidisciplinary models. It manages multiple single discipline component
models and the connections between them. It provides a top-level interface for constructing and evaluating surrogates.
Features
- Manages multidisciplinary models in a graph data structure, supports feedforward and feedback connections
- Feedback connections are solved with a fixed-point iteration (FPI) nonlinear solver
- FPI uses Anderson acceleration and surrogate evaluations for speed-up
- Top-level interface for training and using surrogates of each component model
- Adaptive experimental design for choosing training data efficiently
- Convenient testing, plotting, and performance metrics provided to assess quality of surrogates
- Detailed logging and traceback information
- Supports parallel execution with OpenMP and MPI protocols
- Abstract and flexible interfacing with component models
Model specification
Models are callable Python wrapper functions of the form ret = model(x, *args, **kwargs)
, where x
is an
np.ndarray
of model inputs (and *args, **kwargs
allow passing any other required configurations for your model).
The return value is a Python dictionary of the form ret = {'y': y, 'files': files, 'cost': cost, etc.}
. In the
return dictionary, you specify the raw model output y
as an np.ndarray
at a minimum. Optionally, you can
specify paths to output files and the average model cost (in seconds of cpu time), and anything else you want. Your
model()
function can do anything it wants in order to go from x
→ y
. Python has the flexibility to call
virtually any external codes, or to implement the function natively with numpy
.
Component specification
A component adds some extra configuration around a callable model
. These configurations are defined in a Python
dictionary, which we give the custom type ComponentSpec
. At a bare minimum, you must specify a callable
model
and its connections to other models within the multidisciplinary system. The limiting case is a single
component model, for which the configuration is simply component = ComponentSpec(model)
.
ComponentSpec(model, name='', exo_in=None, coupling_in=None, coupling_out=None, truth_alpha=(), max_alpha=(), max_beta=(), surrogate='lagrange', model_args=(), model_kwargs=None, save_output=False)
Bases: UserDict
Provides a simple extension class of a Python dictionary, used to configure a component model.
Specifying a list of random variables
The three fields: exo_in
, coupling_in
, and coupling_out
fully determine how a component fits within a
multidisciplinary system. For each, you must specify a list of variables in the same order as the model uses
them. The model will use all exogenous inputs first, and then all coupling inputs. You can use a variable's
global integer index into the system exo_vars
or coupling_vars
, or you can use the str
id of the variable
or the variable itself. This is summarized in the amisc.IndicesRV
custom type.
Example
Let's say you have a model:
def my_model(x, *args, **kwargs):
print(x.shape) # (3,), so a total of 3 inputs
G = 6.674e-11
m1 = x[0] # System-level input
m2 = x[1] # System-level input
r = x[2] # Coupling input
F = G*m1*m2 / r**2
return {'y': F}
m1
and m2
are specified by the system, and r
comes
from a different model that predicts the distance between two objects. You would set the configuration as:
Construct the configuration for this component model.
Warning
Always specify the model at a global scope, i.e. don't use lambda
or nested functions. When saving to
file, only a symbolic reference to the function signature will be saved, which must be globally defined
when loading back from that save file.
PARAMETER | DESCRIPTION |
---|---|
model |
the component model, must be defined in a global scope (i.e. in a module or top-level of a script)
TYPE:
|
name |
the name used to identify this component model
TYPE:
|
exo_in |
specifies the global, system-level (i.e. exogenous/external) inputs to this model
TYPE:
|
coupling_in |
specifies the coupling inputs received from other models
TYPE:
|
coupling_out |
specifies all outputs of this model (which may couple later to downstream models)
TYPE:
|
truth_alpha |
the model fidelity indices to treat as a "ground truth" reference
TYPE:
|
max_alpha |
the maximum model fidelity indices to allow for refinement purposes
TYPE:
|
max_beta |
the maximum surrogate fidelity indices to allow for refinement purposes
TYPE:
|
surrogate |
one of ('lagrange, 'analytical'), or the
TYPE:
|
model_args |
optional arguments to pass to the component model
TYPE:
|
model_kwargs |
optional keyword arguments to pass to the component model
TYPE:
|
save_output |
whether this model will be saving outputs to file
TYPE:
|
Source code in src/amisc/system.py
SystemSurrogate(components, exo_vars, coupling_vars, est_bds=0, save_dir=None, executor=None, stdout=True, init_surr=True, logger_name=None)
Multidisciplinary (MD) surrogate framework top-level class.
Accessing individual components
The ComponentSurrogate
objects that compose SystemSurrogate
are internally stored in the self.graph.nodes
data structure. You can access them with get_component(comp_name)
.
ATTRIBUTE | DESCRIPTION |
---|---|
exo_vars |
global list of exogenous/external inputs for the MD system
TYPE:
|
coupling_vars |
global list of coupling variables for the MD system (including all system-level outputs)
TYPE:
|
refine_level |
the total number of refinement steps that have been made
TYPE:
|
build_metrics |
contains data that summarizes surrogate training progress
TYPE:
|
root_dir |
root directory where all surrogate build products are saved to file
TYPE:
|
log_file |
log file where all logs are written to by default
TYPE:
|
executor |
manages parallel execution for the system
TYPE:
|
graph |
the internal graph data structure of the MD system
TYPE:
|
Construct the MD system surrogate.
Warning
Component models should always use coupling variables in the order they appear in the system-level
coupling_vars
.
PARAMETER | DESCRIPTION |
---|---|
components |
list of components in the MD system (using the ComponentSpec class)
TYPE:
|
exo_vars |
list of system-level exogenous/external inputs |
coupling_vars |
list of all coupling variables (including all system-level outputs) |
est_bds |
number of samples to estimate coupling variable bounds, do nothing if 0
TYPE:
|
save_dir |
root directory for all build products (.log, .pkl, .json, etc.), won't save if None
TYPE:
|
executor |
an instance of a
TYPE:
|
stdout |
whether to log to console
TYPE:
|
init_surr |
whether to initialize the surrogate immediately when constructing
TYPE:
|
logger_name |
the name of the logger to use, if None then uses class name by default
TYPE:
|
Source code in src/amisc/system.py
fit(qoi_ind=None, num_refine=100, max_iter=20, max_tol=0.001, max_runtime=1, save_interval=0, update_bounds=True, test_set=None, n_jobs=1)
Train the system surrogate adaptively by iterative refinement until an end condition is met.
PARAMETER | DESCRIPTION |
---|---|
qoi_ind |
list of system QoI variables to focus refinement on, use all QoI if not specified
TYPE:
|
num_refine |
number of samples of exogenous inputs to compute error indicators on
TYPE:
|
max_iter |
the maximum number of refinement steps to take
TYPE:
|
max_tol |
the max allowable value in relative L2 error to achieve
TYPE:
|
max_runtime |
the maximum wall clock time (hr) to run refinement for (will go until all models finish)
TYPE:
|
save_interval |
number of refinement steps between each progress save, none if 0
TYPE:
|
update_bounds |
whether to continuously update coupling variable bounds during refinement
TYPE:
|
test_set |
TYPE:
|
n_jobs |
number of cpu workers for computing error indicators (on master MPI task), 1=sequential
TYPE:
|
Source code in src/amisc/system.py
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 |
|
get_allocation(idx=None)
Get a breakdown of cost allocation up to a certain iteration number during training (starting at 1).
PARAMETER | DESCRIPTION |
---|---|
idx |
the iteration number to get allocation results for (defaults to last refinement step)
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
|
Source code in src/amisc/system.py
get_component(comp_name)
Return the ComponentSurrogate
object for this component.
PARAMETER | DESCRIPTION |
---|---|
comp_name |
name of the component to return
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
ComponentSurrogate
|
the |
Source code in src/amisc/system.py
get_test_metrics(xt, yt, qoi_ind=None, training=True)
Get relative L2 error metric over a test set.
PARAMETER | DESCRIPTION |
---|---|
xt |
TYPE:
|
yt |
TYPE:
|
qoi_ind |
list of indices of QoIs to get metrics for
TYPE:
|
training |
whether to evaluate the surrogate in training or evaluation mode
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
ndarray
|
|
Source code in src/amisc/system.py
init_system()
Add the coarsest multi-index to each component surrogate.
Source code in src/amisc/system.py
insert_component(component, exo_add=None, qoi_add=None)
Insert a new component into the system.
PARAMETER | DESCRIPTION |
---|---|
component |
specs of new component model
TYPE:
|
exo_add |
variables to add to system exogenous inputs (will be appended to end of |
qoi_add |
system output QoIs to add (will be appended to end of |
Source code in src/amisc/system.py
load_from_file(filename, root_dir=None, executor=None, stdout=True, logger_name=None)
staticmethod
Load a SystemSurrogate
object from file.
PARAMETER | DESCRIPTION |
---|---|
filename |
the .pkl file to load
TYPE:
|
root_dir |
if provided, an
TYPE:
|
executor |
a
TYPE:
|
stdout |
whether to log to console
TYPE:
|
logger_name |
the name of the logger to use, if None then uses class name by default
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
the |
Source code in src/amisc/system.py
plot_allocation(cmap='Blues', text_bar_width=0.06, arrow_bar_width=0.02)
Plot bar charts showing cost allocation during training.
Beta feature
This has pretty good default settings, but it might look terrible for your use. Mostly provided here as a template for making cost allocation bar charts. Please feel free to copy and edit in your own code.
PARAMETER | DESCRIPTION |
---|---|
cmap |
the colormap string identifier for
TYPE:
|
text_bar_width |
the minimum total cost fraction above which a bar will print centered model fidelity text
TYPE:
|
arrow_bar_width |
the minimum total cost fraction above which a bar will try to print text with an arrow; below this amount, the bar is too skinny and won't print any text
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
|
Source code in src/amisc/system.py
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 |
|
plot_slice(slice_idx=None, qoi_idx=None, show_surr=True, show_model=None, model_dir=None, N=50, nominal=None, random_walk=False, from_file=None)
Helper function to plot 1d slices of the surrogate and/or model(s) over the inputs.
PARAMETER | DESCRIPTION |
---|---|
slice_idx |
list of exogenous input variables or indices to take 1d slices of
TYPE:
|
qoi_idx |
list of model output variables or indices to plot 1d slices of
TYPE:
|
show_surr |
whether to show the surrogate prediction
TYPE:
|
show_model |
also plot model predictions, list() of ['best', 'worst', tuple(alpha), etc.]
TYPE:
|
model_dir |
base directory to save model outputs (if specified)
TYPE:
|
N |
the number of points to take in the 1d slice
TYPE:
|
nominal |
TYPE:
|
random_walk |
whether to slice in a random d-dimensional direction or hold all params const while slicing
TYPE:
|
from_file |
path to a .pkl file to load a saved slice from disk
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
|
Source code in src/amisc/system.py
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 |
|
predict(x, max_fpi_iter=100, anderson_mem=10, fpi_tol=1e-10, use_model=None, model_dir=None, verbose=False, training=False, index_set=None, qoi_ind=None, ppool=None)
Evaluate the system surrogate at exogenous inputs x
.
Warning
You can use this function to predict outputs for your MD system using the full-order models rather than the
surrogate, by specifying use_model
. This is convenient because SystemSurrogate
manages all the
coupled information flow between models automatically. However, it is highly recommended to not use
the full model if your system contains feedback loops. The FPI nonlinear solver would be infeasible using
anything more computationally demanding than the surrogate.
PARAMETER | DESCRIPTION |
---|---|
x |
TYPE:
|
max_fpi_iter |
the limit on convergence for the fixed-point iteration routine
TYPE:
|
anderson_mem |
hyperparameter for tuning the convergence of FPI with anderson acceleration
TYPE:
|
fpi_tol |
tolerance limit for convergence of fixed-point iteration
TYPE:
|
use_model |
'best'=highest-fidelity, 'worst'=lowest-fidelity, tuple=specific fidelity, None=surrogate, specify a
TYPE:
|
model_dir |
directory to save model outputs if
TYPE:
|
verbose |
whether to print out iteration progress during execution
TYPE:
|
training |
whether to call the system surrogate in training or evaluation mode, ignored if
TYPE:
|
index_set |
TYPE:
|
qoi_ind |
list of qoi indices to return, defaults to returning all system
TYPE:
|
ppool |
a joblib
DEFAULT:
|
RETURNS | DESCRIPTION |
---|---|
ndarray
|
|
Source code in src/amisc/system.py
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 |
|
refine(qoi_ind=None, num_refine=100, update_bounds=True, ppool=None)
Find and refine the component surrogate with the largest error on system-level QoI.
PARAMETER | DESCRIPTION |
---|---|
qoi_ind |
indices of system QoI to focus surrogate refinement on, use all QoI if not specified
TYPE:
|
num_refine |
number of samples of exogenous inputs to compute error indicators on
TYPE:
|
update_bounds |
whether to continuously update coupling variable bounds
TYPE:
|
ppool |
a
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
tuple
|
a tuple of |
Source code in src/amisc/system.py
680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 |
|
sample_inputs(size, comp='System', use_pdf=False, nominal=None, constants=None)
Return samples of the inputs according to provided options.
PARAMETER | DESCRIPTION |
---|---|
size |
tuple or integer specifying shape or number of samples to obtain
TYPE:
|
comp |
which component to sample inputs for (defaults to full system exogenous inputs)
TYPE:
|
use_pdf |
whether to sample from each variable's pdf, defaults to random samples over input domain instead
TYPE:
|
nominal |
TYPE:
|
constants |
set of param types to hold constant while sampling (i.e. calibration, design, etc.), can also put a
TYPE:
|
RETURNS | DESCRIPTION |
---|---|
ndarray
|
|
Source code in src/amisc/system.py
save_to_file(filename, save_dir=None)
Save the SystemSurrogate
object to a .pkl
file.
PARAMETER | DESCRIPTION |
---|---|
filename |
filename of the
TYPE:
|
save_dir |
overrides existing surrogate root directory if provided, otherwise defaults to '.'
TYPE:
|
Source code in src/amisc/system.py
set_executor(executor)
Set a new concurrent.futures.Executor
object for parallel calls.
PARAMETER | DESCRIPTION |
---|---|
executor |
the new
TYPE:
|
Source code in src/amisc/system.py
set_logger(name=None, log_file=None, stdout=True)
Set a new logging.Logger
object with the given unique name
.
PARAMETER | DESCRIPTION |
---|---|
name |
the name of the new logger object
TYPE:
|
stdout |
whether to connect the logger to console (default)
TYPE:
|
log_file |
log file (if provided)
TYPE:
|
Source code in src/amisc/system.py
set_root_directory(root_dir=None, stdout=True, logger_name=None)
Set the root to a new directory, for example if you move to a new filesystem.
PARAMETER | DESCRIPTION |
---|---|
root_dir |
new root directory, don't save build products if None
TYPE:
|
stdout |
whether to connect the logger to console (default)
TYPE:
|
logger_name |
the logger name to use, defaults to class name
TYPE:
|
Source code in src/amisc/system.py
swap_component(component, exo_add=None, exo_remove=None, qoi_add=None, qoi_remove=None)
Swap a new component into the system, updating all connections/inputs.
Beta feature, proceed with caution
If you are swapping a new component in, you cannot remove any inputs that are expected by other components, including the coupling variables output by the current model.
PARAMETER | DESCRIPTION |
---|---|
component |
specs of new component model (must replace an existing component with matching
TYPE:
|
exo_add |
variables to add to system exogenous inputs (will be appended to end) |
exo_remove |
indices of system exogenous inputs to delete (can't be shared by other components)
TYPE:
|
qoi_add |
system output QoIs to add (will be appended to end of |
qoi_remove |
indices of system
TYPE:
|
Source code in src/amisc/system.py
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
|