/
getModelFieldsForType.m
178 lines (159 loc) · 7.89 KB
/
getModelFieldsForType.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
function [matchingFields,dimensions] = getModelFieldsForType(model, type, varargin)
% Get the fields in the model which are associated with the given type.
% USAGE:
% matchingFields = getModelFieldsForType(model, type, varargin)
%
% INPUTS:
%
% model: the model to update
% type: the Type of field to update one of
% ('rxns','mets','comps','genes','ctrs','evars')
%
% OPTIONAL INPUTS:
% varargin: Additional Options as 'ParameterName', Value pairs. Options are:
%
% - 'fieldSize', the original size of the field (if
% mets was already adjusted, this size will be used
% to determine matching fields.
%
% OUTPUT:
%
% matchingfields: A cell array of fields associated with the
% given type. The initial check is for the size of the field, if
% multiple base fields have the same size, it is
% assumed, that fields named e.g. rxnXYZ are
% associated with rxns, and only those fields are
% adapted along with fields which are specified in the
% Model FieldDefinitions.
% dimensions: The dimension associated with the given type in the
% given field. matchingField(X) is matching to type in
% dimenion(X)
% .. Authors:
% - Thomas Pfau June 2017, adapted to merge all fields.
PossibleTypes = {'rxns','mets','comps','genes','evars','ctrs'};
parser = inputParser();
parser.addRequired('model',@(x) isfield(x,type));
parser.addRequired('type',@(x) any(ismember(PossibleTypes,x)));
parser.addOptional('fieldSize',numel(model.(type)),@isnumeric)
parser.parse(model,type,varargin{:});
fieldSize = parser.Results.fieldSize;
%There are a few predefined fields which are NOT associated with one of the
%possible fields.
%First, we retrieve all defined fields.
distinctfields = setdiff(PossibleTypes,type);
sameSizeExists = false;
for i = 1:numel(distinctfields)
if isfield(model,distinctfields{i}) && (numel(model.(distinctfields{i})) == fieldSize)
sameSizeExists = true;
break;
end
end
modelFields = fieldnames(model);
definedFields = getDefinedFieldProperties();
%Collect all fields of the given size
possibleFields = {};
dimensions = [];
if fieldSize == 1 || fieldSize == 0
%This is special. We will only check the first dimension in this
%instance, and we will check the field properties of S and
%rxnGeneMat, Also, we will ONLY return defined fields, or fields with a clear starting ID...
[multiDimFields,firstDim,secondDim] = getMultiDimensionFields(definedFields);
for i = 1:numel(multiDimFields)
cMultiDimField = multiDimFields{i};
if isfield(model, cMultiDimField)
if (strcmp(type, firstDim{i}) && size(model.(cMultiDimField),1) == fieldSize)
possibleFields{end+1,1} = cMultiDimField;
dimensions(end+1,1) = 1;
end
if (strcmp(type, secondDim{i}) && size(model.(cMultiDimField),2) == fieldSize)
possibleFields{end+1,1} = cMultiDimField;
dimensions(end+1,1) = 2;
end
end
end
modelFields = setdiff(modelFields,multiDimFields);
for i = 1:numel(modelFields)
if size(model.(modelFields{i}),1) == fieldSize
possibleFields{end+1,1} = modelFields{i};
dimensions(end+1,1) = 1;
end
end
%This is a New empty model, we only look at defined fields.
fields = definedFields;
fields = fields(cellfun(@(x) isequal(x,type),fields(:,3)) | cellfun(@(x) isequal(x,type),fields(:,2)),1);
%modelFields with the "correct" startingID
relModelFields = modelFields(cellfun(@(x) strncmp(x,type,length(type-1)),modelFields)); %Remove the s from the type for this
fields = columnVector(union(fields,relModelFields));
posFields = ismember(possibleFields,fields);
possibleFields = possibleFields(posFields);
dimensions = dimensions(posFields);
else
knownfields = definedFields;
firstdim = cellfun(@(x,y) isequal(x,type) && isfield(model,y) && (size(model.(y),1) == fieldSize),knownfields(:,2), knownfields(:,1));
seconddim = cellfun(@(x,y) isequal(x,type) && isfield(model,y) && (size(model.(y),2) == fieldSize),knownfields(:,3), knownfields(:,1));
%Remove the known fields.
unknownModelFields = setdiff(modelFields,knownfields(:,1));
%And get all matching fields
knownMatchingFields = knownfields((firstdim|seconddim),1);
%Only look at known fields which are defined, or undefined fields
modelFields = union(unknownModelFields,knownMatchingFields);
for i = 1:numel(modelFields)
matchingsizes = size(model.(modelFields{i})) == fieldSize;
if any(matchingsizes) && ~(sum(matchingsizes) > 1) %A size > 1 should only happen if we have conflicting field sizes...
possibleFields{end+1,1} = modelFields{i};
dimensions(end+1,1) = find(matchingsizes);
elseif sum(matchingsizes) > 1
%Now we have a problem. We have multiple dimensions that could fit
%to the found element.
%if there is an element of the same size, we will have to
%resort to using the defined properties (i.e. we will add it
%with a dimension of -1 (that we can replace by the definition
%later)
if sameSizeExists
possibleFields{end+1,1} = modelFields{i};
dimensions(end+1,1) = -1;
else
%Otherwise, we add both dimensions, as it seems like this
%is a type x type field.
cdmins = find(matchingsizes);
for dim = 1:numel(cdmins)
possibleFields{end+1,1} = modelFields{i};
dimensions(end+1,1) = cdmins(dim);
end
end
end
end
end
if sameSizeExists
%we restrict the possibleFields to those which start with the
%indicator, along with those fields, which are part of the defined
%fields.
fields = definedFields;
firstdim = cellfun(@(x,y) isequal(x,type) && isfield(model,y) && (size(model.(y),1) == fieldSize),fields(:,2), fields(:,1));
seconddim = cellfun(@(x,y) isequal(x,type) && isfield(model,y) && (size(model.(y),2) == fieldSize),fields(:,3), fields(:,1));
definedFieldDims = ones(numel(fields(:,1)),1);
definedFieldDims(seconddim) = 2;
fields = fields( firstdim | seconddim ,1);
definedFieldDims = definedFieldDims(firstdim | seconddim);
definedPossibles = ismember(fields,possibleFields);
%Reduce the fields to those which match the size AND are defined.
definedFieldDims = definedFieldDims(definedPossibles);
fields = fields(definedPossibles);
%Now, check again the if the sizes fit...
actualFieldDimsMatch = arrayfun(@(x) size(model.(fields{x}),definedFieldDims(x)) == fieldSize, 1:numel(fields));
definedFieldDims = definedFieldDims(actualFieldDimsMatch);
fields = fields(actualFieldDimsMatch);
%Now check the relevant field positions in the possible fields, i.e.
%those starting with the respective id (e.g. rxn).
%However, we should only include those which are not defined.
%i.e. everything with field... and not defined.
undefinedFields = ~(ismember(possibleFields,definedFields(:,1))) & cellfun(@(x) strncmp(x,type,length(type)-1),possibleFields);
undefDims = dimensions(undefinedFields);
undefpossibleFieldNames = possibleFields(undefinedFields);
dimensions = [definedFieldDims;undefDims];
possibleFields = [fields; undefpossibleFieldNames];
%Now, we also need to take care of rxnGeneMat and S, otherwise we could
%end up in a critical spot.
end
matchingFields = possibleFields;
end