|
| 1 | +function [solICONGEMs, boundEf] = ICONGEMs(model, exp, genetxt, condition, threshold, alpha) |
| 2 | +% Algorithm to Integrate a Gene Co-expression Network and Genome-scale Metabolic Model: |
| 3 | +% This algorithm calculates the reaction flux distribution for each condition by applying |
| 4 | +% quadratic programming. |
| 5 | +% |
| 6 | +% USAGE: |
| 7 | +% |
| 8 | +% [solICONGEMs, boundEf] = ICONGEMs(model, exp, genetxt, condition, threashold, alpha) |
| 9 | +% |
| 10 | +% INPUTS: |
| 11 | +% |
| 12 | +% model: input model (COBRA model structure) |
| 13 | +% exp: expression profile corresponding to the gene names that |
| 14 | +% extract from gene expression profile file |
| 15 | +% genetxt: list of gene names that extract from gene expression profile |
| 16 | +% file |
| 17 | +% |
| 18 | +% OPTIONAL INPUTS: |
| 19 | +% threshold: The value of the correlation coefficient for constructing |
| 20 | +% the co-expression network (default value: 0.9). |
| 21 | +% condition: Row vector indicating the number of conditions |
| 22 | +% corresponding to the conditions in exp |
| 23 | +% (default value: 1:size(exp, 2)). |
| 24 | +% alpha: The value for the proportion of biomass (default value: 1). |
| 25 | +% |
| 26 | +% OUTPUTS: |
| 27 | +% solICONGEMs: Flux distribution table corresponding to reaction flux names. |
| 28 | +% boundEf: Upper bound of E-flux. |
| 29 | +% |
| 30 | +% EXAMPLES: |
| 31 | +% % This could be an example that can be copied from the documentation to MATLAB: |
| 32 | +% solution = ICONGEMs(model, exp, genetxt, condition, threashold, alpha) |
| 33 | +% % without optional values: |
| 34 | +% solution = ICONGEMs(model, exp, genetxt) |
| 35 | +% |
| 36 | +%..Author: |
| 37 | +% -Thummarat Paklao, 01/02/2024, Department of Mathematics and Computer Science, Faculty of Science, Chulalongkorn University, Thailand. |
| 38 | +% -Apichat Suratanee, 01/02/2024, Department of Mathematics, Faculty of Applied Science, King Mongkut's University of Technology North Bangkok. |
| 39 | +% -Kitiporn Plaimas, 01/02/2024, Department of Mathematics and Computer Science, Faculty of Science, Chulalongkorn University, Thailand. |
| 40 | + |
| 41 | +if (nargin < 4 || isempty(condition)) |
| 42 | + condition = 1:size(exp, 2); |
| 43 | +end |
| 44 | +if (nargin < 5 || isempty(threshold)) |
| 45 | + threshold = 0.9; |
| 46 | +end |
| 47 | +if (nargin < 6 || isempty(alpha)) |
| 48 | + alpha = 0.99; |
| 49 | +end |
| 50 | + |
| 51 | +% construct the template model |
| 52 | + |
| 53 | +modelN = model; |
| 54 | +modelN.lb(modelN.lb >= 0) = 0; |
| 55 | +modelN.lb(modelN.lb < 0) = -1000; |
| 56 | +modelN.ub(modelN.ub <= 0) = 0; |
| 57 | +modelN.ub(modelN.ub > 0) = 1000; |
| 58 | + |
| 59 | +% convert to irreversible format |
| 60 | + |
| 61 | +[modelIrrev, matchRev, rev2irrev, irrev2rev] = convertToIrreversible(modelN); |
| 62 | + |
| 63 | +% Check that the gene names in the gene expression profile agree with |
| 64 | +% the gene names in the metabolic model. |
| 65 | + |
| 66 | +geneinMet = zeros(size(genetxt, 1) - 1, 1); |
| 67 | +for i = 2:size(genetxt, 1) |
| 68 | + for j = 1:size(modelIrrev.genes, 1) |
| 69 | + if string(genetxt(i)) == string(modelIrrev.genes(j)) |
| 70 | + geneinMet(i - 1) = 1; |
| 71 | + end |
| 72 | + end |
| 73 | +end |
| 74 | +if sum(sum(geneinMet)) == 0 |
| 75 | + disp("gene name in gene expression data is not agree gene name in metabolic model") |
| 76 | +end |
| 77 | + |
| 78 | +% Choose only the gene expression profiles that match genes in the metabolic model. |
| 79 | + |
| 80 | +exp1 = exp(geneinMet == 1, :); |
| 81 | +txt2 = genetxt([0; geneinMet] == 1, 1); |
| 82 | + |
| 83 | +% remove missing data |
| 84 | + |
| 85 | +[exp1, TF] = rmmissing(exp1, 1); |
| 86 | +txt2 = txt2(~TF, 1); |
| 87 | +geneincoexnet = modelIrrev.genes(~TF); |
| 88 | + |
| 89 | +% Construct co-expression network |
| 90 | + |
| 91 | +cor = corr((exp1)'); |
| 92 | +cor1 = cor >= threshold; |
| 93 | + |
| 94 | +% Find gene pairs that have a high correlation in the co-expression network. |
| 95 | + |
| 96 | +indCorGene = zeros(1, 2); |
| 97 | +l = 1; |
| 98 | +for i = 1:size(cor, 1) |
| 99 | + for j = i:size(cor,1) |
| 100 | + if (cor1(i,j) ~= 0) && (i ~= j) |
| 101 | + indCorGene(l, 1) = i; |
| 102 | + indCorGene(l, 2) = j; |
| 103 | + l = l + 1; |
| 104 | + end |
| 105 | + end |
| 106 | +end |
| 107 | + |
| 108 | +coGene = cell(size(indCorGene, 1), 2); |
| 109 | +coGene(:, 1) = geneincoexnet(indCorGene(:, 1), 1); |
| 110 | +coGene(:, 2) = geneincoexnet(indCorGene(:, 2), 1); |
| 111 | + |
| 112 | +NameRxn={}; |
| 113 | +for i = 1:size(modelIrrev.genes) |
| 114 | + [z1, NameRxn{i}] = findRxnsFromGenes(modelIrrev, modelIrrev.genes(i, 1), [], 1); |
| 115 | +end |
| 116 | + |
| 117 | +% Find reactions that correspond to the gene |
| 118 | + |
| 119 | +NameCorRxn = {}; |
| 120 | +for i = 1:size(coGene, 1) |
| 121 | + NameCorRxn{i, 1} = NameRxn{find(modelIrrev.genes == string(coGene(i, 1)))}; |
| 122 | + NameCorRxn{i, 2} = NameRxn{find(modelIrrev.genes == string(coGene(i, 2)))}; |
| 123 | +end |
| 124 | + |
| 125 | +f = 0; |
| 126 | +h = 0; |
| 127 | +indCorRxn = zeros(10, 2); |
| 128 | +for i = 1:size(NameCorRxn, 1) |
| 129 | + if (~isempty(NameCorRxn{i, 1}) && ~isempty(NameCorRxn{i, 2})) |
| 130 | + for j = 1:size(NameCorRxn{i, 1}, 1) |
| 131 | + f = f + size(NameCorRxn{i, 2}, 1); |
| 132 | + indCorRxn(h + 1 : h + size(NameCorRxn{i, 2}, 1), 1) = findRxnIDs(modelIrrev, NameCorRxn{i, 1}{j, 1}); |
| 133 | + for w = 1:size(NameCorRxn{i, 2}, 1) |
| 134 | + indCorRxn(h + w,2)=findRxnIDs(modelIrrev,NameCorRxn{i, 2}{w, 1}); |
| 135 | + end |
| 136 | + h = f; |
| 137 | + end |
| 138 | + end |
| 139 | +end |
| 140 | + |
| 141 | +% Construct a reaction pair matrix. |
| 142 | + |
| 143 | +R = zeros(length(modelIrrev.rxns),length(modelIrrev.rxns)); |
| 144 | +for i = 1:size(indCorRxn, 1) |
| 145 | + if indCorRxn(i, 1) ~= indCorRxn(i, 2) |
| 146 | + R(indCorRxn(i, 1), indCorRxn(i, 2)) = 1; |
| 147 | + end |
| 148 | +end |
| 149 | + |
| 150 | +% Construct an irreversible reaction matrix from the reversible reactions |
| 151 | +% that are decomposed into the same components. |
| 152 | + |
| 153 | +Re = zeros(size(R)); |
| 154 | +for i = 1:length(model.rxns) |
| 155 | + if length(rev2irrev{i, 1}) == 2 |
| 156 | + Re(i, rev2irrev{i,1}(2)) = 1; |
| 157 | + end |
| 158 | +end |
| 159 | + |
| 160 | +% Process gene expression data based on Gene-Protien-Reaction (GPR) associations. |
| 161 | + |
| 162 | +geneExdat = zeros(length(modelIrrev.genes), 1); |
| 163 | +nupb = zeros(length(modelIrrev.rules), size(exp, 2)); |
| 164 | +for ch = 1:size(exp, 2) |
| 165 | +for i = 1:length(modelIrrev.genes) |
| 166 | + cc = 0; |
| 167 | + for j = 1:length(genetxt(:, 1)) - 1 |
| 168 | + if string(modelIrrev.genes(i)) == string(genetxt(j + 1, 1)) |
| 169 | + geneExdat(i) = exp(j, ch); |
| 170 | + cc = cc + 1; |
| 171 | + end |
| 172 | + end |
| 173 | + if geneExdat(i) == 0 && cc == 0 |
| 174 | + geneExdat(i) = 1000; |
| 175 | + end |
| 176 | +end |
| 177 | + |
| 178 | +for i = 1:length(modelIrrev.rules) |
| 179 | + rulegene = modelIrrev.rules{i}; |
| 180 | + if isempty(rulegene) |
| 181 | + rsum = 1000; |
| 182 | + else |
| 183 | + newrule = split(rulegene,"|"); |
| 184 | + nrule = size(newrule, 1); |
| 185 | + rsum = 0; |
| 186 | + for j = 1:nrule |
| 187 | + newrule1 = newrule{j}; |
| 188 | + nnrule = length(newrule1); |
| 189 | + rmin = inf; |
| 190 | + for k = 1:nnrule |
| 191 | + if newrule1(k) == 'x' |
| 192 | + r1 = k+2; |
| 193 | + end |
| 194 | + if (newrule1(k) == ')' && newrule1(k-1) ~= ' ' && newrule1(k - 1) ~= ')') |
| 195 | + rmin = min(rmin, geneExdat(str2num(convertCharsToStrings((newrule1(r1:k - 1)))))); |
| 196 | + end |
| 197 | + end |
| 198 | + rsum = rsum + rmin; |
| 199 | + end |
| 200 | + end |
| 201 | + nupb(i, ch) = rsum; |
| 202 | +end |
| 203 | + |
| 204 | +end |
| 205 | +PosNupb = nupb >= 1000; |
| 206 | +nupb(PosNupb) = max(nupb(~PosNupb)); |
| 207 | + |
| 208 | +% Construct a table for reporting the results |
| 209 | + |
| 210 | +solution = table(model.rxns); |
| 211 | +solutionFull = table(modelIrrev.rxns); |
| 212 | +solutionEf = table(model.rxns); |
| 213 | +solutionEfFull = table(modelIrrev.rxns); |
| 214 | +n = 0; |
| 215 | + |
| 216 | +% Construct the model and calculate the flux distribution. |
| 217 | + |
| 218 | +for ch = condition |
| 219 | + n = n + 1; |
| 220 | +disp("Condition :"); disp(ch); |
| 221 | +model3 = changeRxnBounds(modelIrrev,modelIrrev.rxns, nupb(:, ch), 'u'); |
| 222 | +solution1 = optimizeCbModel(model3); |
| 223 | + |
| 224 | +Trans0 = zeros(size(modelIrrev.mets, 1),size(modelIrrev.rxns, 1)); |
| 225 | +Trans2 = -1 * eye(size(modelIrrev.rxns, 1)); |
| 226 | +S2 = zeros(size(modelIrrev.rxns, 1)); |
| 227 | +for i = 1:length(modelIrrev.rxns) |
| 228 | + S2(i, i) = 1 / max(nupb(i, :)); |
| 229 | +end |
| 230 | + |
| 231 | + |
| 232 | +Obj4 = [modelIrrev.c' zeros(1, size(modelIrrev.rxns, 1))] ; |
| 233 | + |
| 234 | +lob = [model3.lb; (-1) * inf * ones(size(modelIrrev.rxns, 1), 1)]; |
| 235 | +upb = [model3.ub; inf * ones(size(modelIrrev.rxns, 1), 1)]; |
| 236 | + |
| 237 | +O = [zeros(size(R)) zeros(size(R)); zeros(size(R)) R]; |
| 238 | +Aeq = [modelIrrev.S Trans0; S2 Trans2; Obj4]; |
| 239 | +beq = [zeros(size(modelIrrev.mets, 1), 1); (-1) * ones(size(modelIrrev.rxns,1),1); alpha * solution1.f]; |
| 240 | + |
| 241 | +model2 = struct; |
| 242 | +model2.lb = lob; |
| 243 | +model2.ub = upb; |
| 244 | +model2.A = sparse(Aeq); |
| 245 | +model2.sense = [char('=' * ones(size(model2.A,1) - 1, 1)) ; char('>')]; |
| 246 | +model2.rhs = beq; |
| 247 | +model2.modelsense = 'min'; |
| 248 | +numrxn = [1:length(modelIrrev.rxns)]; |
| 249 | +j = 1; |
| 250 | +for i = 1:length(model.rxns) |
| 251 | + if length(Re(Re(i, :)>0)) == 1 |
| 252 | +model2.quadcon(j).Qrow = i; |
| 253 | +model2.quadcon(j).Qcol = numrxn(Re(i, :)>0); |
| 254 | +model2.quadcon(j).Qval = 1.0; |
| 255 | +model2.quadcon(j).rhs = 0.0; |
| 256 | +model2.quadcon(j).q = sparse(zeros(2*size(Re, 1), 1)); |
| 257 | +model2.quadcon(j).sense = '='; |
| 258 | +j = j + 1; |
| 259 | + end |
| 260 | +end |
| 261 | +model2.Q = sparse(O); |
| 262 | +params.NonConvex = 2; |
| 263 | +result = gurobi(model2, params); |
| 264 | +x = result.x; |
| 265 | +solutionFull(:, n + 1) = table(x(1:size(modelIrrev.rxns),1)); |
| 266 | +solutionEfFull(:, n + 1) = table(solution1.x); |
| 267 | +solFlux = []; |
| 268 | +solFluxEf = []; |
| 269 | +for i = 1:length(model.rxns) |
| 270 | + if length(rev2irrev{i, 1}) == 1 |
| 271 | + solFlux(i, 1) = x(i, 1); |
| 272 | + solFluxEf(i, 1) = solution1.x(i, 1); |
| 273 | + else |
| 274 | + solFlux(i, 1) = (x(rev2irrev{i, 1}(1, 1))-x(rev2irrev{i, 1}(1, 2))); |
| 275 | + solFluxEf(i, 1) = (solution1.x(rev2irrev{i, 1}(1, 1))-solution1.x(rev2irrev{i, 1}(1, 2))); |
| 276 | + if solFluxEf(i, 1)>=0 |
| 277 | + solutionEfFull{rev2irrev{i, 1}(1, 1), n + 1} = solFluxEf(i, 1); |
| 278 | + solutionEfFull{rev2irrev{i, 1}(1, 2), n + 1} = 0; |
| 279 | + elseif solFluxEf(i, 1)<0 |
| 280 | + solutionEfFull{rev2irrev{i, 1}(1, 1), n + 1} = 0; |
| 281 | + solutionEfFull{rev2irrev{i, 1}(1, 2), n + 1} = abs(solFluxEf(i, 1)); |
| 282 | + |
| 283 | + end |
| 284 | + end |
| 285 | +end |
| 286 | +solution(:, n + 1) = table(solFlux); |
| 287 | +solutionEf(:, n + 1) = table(solFluxEf); |
| 288 | + |
| 289 | +end |
| 290 | +boundEf = table(nupb); |
| 291 | +solICONGEMs.sol = solution; |
| 292 | +solICONGEMs.solRev = solutionFull; |
| 293 | + |
| 294 | +solEflux.sol = solutionEf; |
| 295 | +solEflux.solRev = solutionEfFull; |
| 296 | + |
| 297 | +% Export the results |
| 298 | + |
| 299 | +filename = 'result.csv'; |
| 300 | +writetable(solution, filename) |
| 301 | +end |
| 302 | + |
0 commit comments