Optional: Coding 6
This optional section explores the ensemble
class in greater depth. This section is intended for users who are interested in the full capabilities of the ensemble
class, particularly users who are already familiar with using the DASH toolbox. You can skip this section if this is your first time using DASH. Some of these commands do appear later in the tutorial, but they will be discussed as they arise.
Goal
Practice using ensemble
commands.
Step 1: Create ensemble
object
You can use the ensemble
command to create an ensemble object for a saved state vector ensemble. The syntax is:
obj = ensemble(filename)
where filename is the name of the saved ensemble file. The name should either be the name of a file on the active path, or an absolute file name. If you do not include a .ens
extension, the method will apply one automatically.
If the stateVector
object used to build the ensemble had a label, then the ensemble object will automatically be given that label. You can optionally use the second input to apply a different label to the object:
obj = ensemble(filename, label)
Tip
You can also use the ensemble.label
command at any later point to re-label the ensemble.
Recall that we saved the demo state vector ensemble in a file named ntrend.ens
. We’ll create an ensemble object for the saved ensemble:
file = "ntrend.ens";
ens = ensemble(file);
Inspecting the object:
disp(ens)
static ensemble with properties:
Label: NTREND Temperature Demo
Variables: T, T_index, T_monthly
Length: 56161
Members: 1156
we can see the saved state vector ensemble.
Step 2: Load data
Use the load
command to load data from the saved ensemble. The syntax is:
[X, metadata] = obj.load
- X
The first output is a numeric matrix. This is the loaded state vector ensemble. The columns of the matrix are ensemble members, and each row is a state vector element.
- metadata
The second output is an
ensembleMetadata
object that describes the loaded array.
We’ll use the load
command to load the saved state vector ensemble:
ens = ensemble("ntrend.ens");
[X, metadata] = ens.load;
Examining the data array:
size(X)
ans =
56161 1156
we can see that the first output is a matrix with 56161 state vector elements, and 1156 ensemble members. The second output:
disp(metadata)
ensembleMetadata with properties:
Label: NTREND Temperature Demo
Variables: T, T_index, T_monthly
Length: 56161
Members: 1156
Vector:
T - 4320 rows | lon (144) x lat (30)
T_index - 1 rows | lon (1) x lat (1)
T_monthly - 51840 rows | lon (144) x lat (30) x time sequence (12)
records information about the loaded ensemble.
Step 3: Return Metadata
It’s often useful to return the metadata object for an ensemble without actually loading the ensemble. You can use the metadata
command to return the metadata object. The syntax is:
metadata = obj.metadata
Here, we’ll return the metadata object for the saved ensemble:
% Load the metadata
ens = ensemble("ntrend");
metadata = ens.metadata;
% Display in console
disp(metadata)
ensembleMetadata with properties:
Label: NTREND Temperature Demo
Variables: T, T_index, T_monthly
Length: 56161
Members: 1156
Vector:
T - 4320 rows | lon (144) x lat (30)
T_index - 1 rows | lon (1) x lat (1)
T_monthly - 51840 rows | lon (144) x lat (30) x time sequence (12)
Step 4: Select Variables
Use the useVariables
command to limit the ensemble object to a specific set of variables. Here the syntax is:
obj = obj.useVariables(variables)
- variables
The input is a list of variables in the ensemble. You can either list variable names, or the indices of variables within the ensemble. Using
-1
will reselect all the variables in the ensemble.- obj
The output is the updated ensemble object.
After using the useVariables
command, the load
command will only load data for the specified variables. Likewise, the metadata
command will only return metadata for these variables.
We’ll use the useVariables
command to limit the ensemble to the reconstruction targets - the T and T_index variables:
variables = ["T", "T_index"];
ens = ens.useVariables(variables);
Inspecting the object:
disp(ens)
static ensemble with properties:
Label: NTREND Temperature Demo
Variables: T, T_index
Length: 4321
Members: 1000
we can see that it only represents the two listed variables.
If we now call the load
command and examine the output:
[X, metadata] = ens.load;
siz = size(X)
siz =
4321 1156
we can see that the loaded matrix only includes the 4321 rows associated with the T and T_index variables. It does not include the remaining rows associated with the T_monthly variable.
Likewise the metadata object only includes information on the loaded variables:
disp(metadata)
ensembleMetadata with properties:
Label: NTREND Temperature Demo
Variables: T, T_index
Length: 4321
Members: 1156
Vector:
T - 4320 rows | lon (144) x lat (30)
T_index - 1 rows | lon (1) x lat (1)
Step 5: Select Members
Use the useMembers
command to limit the ensemble object to a specific set of ensemble members. Here the syntax is:
obj = obj.useMembers(members)
- members
The input is a vector of indices pointing to specific ensemble members in the saved state vector ensemble. Both linear and logical indices are acceptable. Using
-1
will reselect all saved ensemble members.- obj
The output is the updated ensemble object.
After using the useMembers
command, the load
command will only load data for the specified members. Likewise, the metadata
command will only return metadata for these members.
This command is often combined with the ensembleMetadata.members
command, which returns metadata for the members of an ensemble. This metadata can be used identify and select specific members within the ensemble. The base syntax for this command is:
metadata = obj.members(dimension)
- dimension
The first input is the name of an ensemble dimension for which to return metadata.
- metadata
The output is the metadata at the reference point for each ensemble member. The metadata will be a matrix with one row per ensemble member.
Here, we’ll limit the ensemble to 100 randomly selected ensemble members. We’ll use Matlab’s randsample
command to select 100 members from the 1156 member ensemble:
% (Reset the random number generator to make the demo reproducible)
rng('default')
% Select 100 members at random
members = randsample(1156, 100);
% Create an ensemble object that uses the 100 members
ens = ensemble('ntrend');
ens = ens.useMembers(members);
Examining the ensemble object:
disp(ens)
static ensemble with properties:
Label: NTREND Temperature Demo
Variables: T, T_index, T_monthly
Length: 56161
Members: 100
we see it now represents an ensemble with 100 members.
If we now call the load
command and examine the output:
[X, metadata] = ens.load;
siz = size(X)
siz =
56161 100
we can see that the loaded matrix only include the 100 columns (ensemble members) associated with the object. Likewise the metadata object only records values for 100 members:
disp(metadata)
ensembleMetadata with properties:
Label: NTREND Temperature Demo
Variables: T, T_index, T_monthly
Length: 56161
Members: 100
We can also use the ensembleMetadata.members
command to see which members were selected:
% Get the time metadata for the 100 members
time = metadata.members("time");
% Display the size and metadata
siz = size(time)
disp(time)
siz =
100 1
time =
100×1 datetime array
15-Jan-1014
15-Jan-1634
15-Jan-1635
...
15-Jan-1562
15-Jan-1010
15-Jan-0962
We can see that the metadata includes metadata for 100 ensemble members, and that the ensemble members are randomly selected from the 1156 January reference points.
Here, we’ll limit the ensemble to members from the pre-industrial era - that is, ensemble members from before 1850. We’ll use the ensembleMetadata.members
method to help locate these members:
% Build an ensemble object and get its metadata object
ens = ensemble('ntrend');
metadata = ens.metadata;
% Get the time metadata for each ensemble member and locate preindustrial members
time = metadata.members("time")
preindustrial = year(time) < 1850;
% Only use the preindustrial ensemble members
ens = ens.useMembers(preindustrial);
Examining the ensemble object:
disp(ens)
static ensemble with properties:
Label: NTREND Temperature Demo
Variables: T, T_index, T_monthly
Length: 56161
Members: 1000
we can see it represents an ensemble with 1000 members. We can use the updated object’s ensembleMetadata
to verify that the ensemble uses the 1000 preindustrial members:
metadata = ens.metadata;
time = metadata.members("time")
1000×1 datetime array
15-Jan-0850
15-Jan-0851
15-Jan-0852
...
15-Jan-1847
15-Jan-1848
15-Jan-1849
Step 6: Evolving Ensemble
You can use the evolving
command to implement an evolving ensemble. Each ensemble in an evolving set is built from a different selection of ensemble members. The syntax for the command is:
obj = obj.evolving(members)
- members
The first input indicates which ensemble members to use in each ensemble of an evolving set. This input is a matrix of indices. Each column lists the members for a particular ensemble in the evolving set. Both linear and logical indices are accepted, but each ensemble should have the same number of members.
- obj
The output is the updated ensemble object.
You can also use the optional second input to provide a set of labels for the ensembles in the evolving set:
obj = obj.evolving(members, labels)
The labels input should be a vector of strings with one label per ensemble.
Tip
You can also use the evolvingLabels
command to apply labels to the evolving ensembles.
This command is often combined with the ensembleMetadata.members
command, which helps locate members for specific ensembles. See the section above for its syntax.
After using the evolving
command, the load
command will return a 3D data array, rather than a data matrix. The rows and columns are the same as before, and elements along the third dimension correspond to ensembles in the evolving set. The output metadata will become a vector of metadata objects with one object per ensemble in the set. The metadata
command will similarly return a vector of metadata objects.
Furthermore, you can now provide an optional input to the load
and metadata
commands. The syntax becomes:
[X, metadata] = obj.load(ensembles)
metadata = obj.metadata(ensembles)
and allows you to return values for specific ensembles in the evolving set. The ensembles input is a list of ensembles for which to return values. You can either list the labels associated with particular ensembles, or the indices of ensembles in the evolving set.
We’ll design an evolving ensemble with three individual ensembles. Each ensemble in the evolving set will be built from a different set of 100 ensemble members. Specifically, the three ensembles will correspond to the years 1200-1299, 1800-1899, and 1900-1999. We’ll label the individual ensembles as “Preindustrial”, “Mixed”, and “Modern”
% Build an ensemble object and get its metadata
ens = ensemble('ntrend');
metadata = ens.metadata;
% Get the time metadata for the ensemble members.
time = metadata.members('time');
time = year(time);
% Select members for the three ensembles
pi = ismember(time, 1200:1299);
mixed = ismember(time, 1800:1899);
modern = ismember(time, 1900:1999);
% Design the evolving ensemble
members = [pi, mixed, modern];
labels = ["Preindustrial" ,"Mixed", "Modern"];
ens = ens.evolving(members, labels);
Examining the ensemble object:
disp(ens)
evolving ensemble with properties:
Label: NTREND Temperature Demo
Variables: T, T_index, T_monthly
Length: 56161
Members: 100 (per ensemble)
Evolving Ensembles: 3
1. Preindustrial
2. Mixed
3. Modern
we can see that the object now represents an evolving ensemble with 3 individual ensembles in the evolving set.
If we call the load command and examine the output:
[X, metadata] = ens.load;
siz = size(X)
siz =
56161 100 3
we can see that the loaded data array has 3 elements along the third dimension - one element per ensemble in the evolving set. Additionally, the array has 100 columns, so each individual ensemble is built from 100 ensemble members.
Examining the metadata:
disp(metadata)
3x1 ensembleMetadata array
Labels:
"Preindustrial"
"Mixed"
"Modern"
we can see that it includes 3 metadata objects - one per ensemble. Finally, we can use the loaded metadata objects to verify the members in each ensemble. For example, for the first (preindustrial) ensemble:
time = metadata(1).members
time =
100×1 datetime array
15-Jan-1200
15-Jan-1201
15-Jan-1202
...
15-Jan-1297
15-Jan-1298
15-Jan-1299
We can also use the load
method to load specific ensembles within the evolving set. Here, we’ll load the Preindustrial and Modern, but not the Mixed (1800-1899) ensemble:
[X, metadata] = ens.load(["Preindustrial", "Modern"])
siz = size(X)
siz =
56161 100 2
disp(metadata)
2x1 ensembleMetadata array
Labels:
"Preindustrial"
"Modern"
Full Demo
% Create ensemble object
file = 'ntrend.ens';
ens = ensemble(file);
% Select variables
variables = ["T", "T_index"];
ens = ens.useVariables(variables);
% Select ensemble members
members = randsample(1000, 100);
ens = ens.useMembers(members);
% Load
[X, metadata] = ens.load;
%%%%%%%%
% Get metadata for ensemble members
ens = ensemble('ntrend');
metadata = ens.metadata;
time = year(metadata.members('time'));
% Locate ensemble members
pi = ismember(time, 1200:1299);
mixed = ismember(time, 1800:1899);
modern = ismember(time, 1900:1999);
% Design the evolving ensemble
members = [pi, mixed, modern];
labels = ["Preindustrial" ,"Mixed", "Modern"];
ens = ens.evolving(members, labels);
% Load specific ensembles in evolving set
[X, metadata] = ens.load(["Preindustrial","Modern"]);