Skip to content

Commit d906aa3

Browse files
authored
Merge pull request #2271 from ThummaratPaklao/addfile_icongems
Addfile icongems
2 parents c4e70df + 71f66ad commit d906aa3

File tree

4 files changed

+377
-0
lines changed

4 files changed

+377
-0
lines changed

src/analysis/ICONGEMs/ICONGEMs.m

+302
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
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+

src/analysis/ICONGEMs/readme.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
% The COBRAToolbox: testICONGEMs.m
2+
%
3+
% Purpose:
4+
% - Tests the ICONGEMs function
5+
%
6+
%..Author:
7+
% -Original file, Thummarat Paklao, Apichat Suratanee, and Kitiporn Plaimas.
8+
9+
global CBTDIR
10+
11+
% set the tolerance
12+
tol = 1e-4;
13+
tol2 = 2e-1;
14+
15+
% define the solver required to run the test
16+
useIfAvailable = {'gurobi'};
17+
18+
% test solver packages
19+
solverPkgs = prepareTest('needsLP', true, 'needsQP', true, 'useSolversIfAvailable', useIfAvailable);
20+
21+
% save the current path
22+
currentDir = pwd;
23+
24+
% initialize the test
25+
fileDir = fileparts(which('testICONGEMs'));
26+
cd(fileDir);
27+
28+
% load model
29+
modelFileName = 'ecoli_core_model.mat';
30+
model = getDistributedModel(modelFileName);
31+
[modelIrrev, matchRev, rev2irrev, irrev2rev] = convertToIrreversible(model);
32+
Re = zeros(size(modelIrrev.rxns,1),size(modelIrrev.rxns,1));
33+
for i = 1:length(model.rxns)
34+
if length(rev2irrev{i, 1}) == 2
35+
Re(i, rev2irrev{i,1}(2)) = 1;
36+
end
37+
end
38+
39+
% load gene expression data
40+
fileName = 'gene_exp.csv';
41+
[exp, txt] = xlsread(fileName);
42+
43+
% set optional parameter
44+
condition1=1:size(exp,2);
45+
threashold = 0.8;
46+
alpha = 0.99;
47+
48+
% test optimizeCbModel in cobratoolbox
49+
50+
sol_fba = optimizeCbModel(model);
51+
52+
for k = 1:length(solverPkgs.QP)
53+
fprintf(' -- Running testICONGEMs using the solver interface: %s ... ', solverPkgs.QP{k});
54+
55+
solverQPOK = changeCobraSolver(solverPkgs.QP{k}, 'QP', 0);
56+
57+
if solverQPOK
58+
[solICONGEMs, solEflux, R, boundEf] = ICONGEMs(model, exp, txt);
59+
for i = 1:size(exp,2)
60+
assert(norm(model.S * table2array(solICONGEMs.sol(:,i+1)) - model.b, 2) < tol);
61+
assert(abs(table2array(solICONGEMs.solRev(:,i+1))' * Re * table2array(solICONGEMs.solRev(:,i+1))) < tol)
62+
assert(abs(model.c' * table2array(solICONGEMs.sol(:,i+1)) - alpha * model.c' * table2array(solEflux.sol(:,i+1))) < tol)
63+
64+
end
65+
66+
end
67+
68+
% output a success message
69+
fprintf('Done.\n');
70+
end
71+
72+
% change the directory
73+
cd(currentDir)

0 commit comments

Comments
 (0)