module reacteqn; % REDUCE support for reaction equations.
% Author: H. Melenk
% January 1991
% Copyright (c) Konrad-Zuse-Zentrum Berlin, all rights reserved.
create!-package('(reacteqn),'(contrib misc));
% Introduce operators for chemical equations.
algebraic operator rightarrow;
newtok '((!- !>) rightarrow);
infix rightarrow;
precedence rightarrow,equal;
algebraic operator doublearrow;
newtok '((!< !>) doublearrow);
infix doublearrow;
precedence doublearrow,equal;
algebraic operator rate;
global '(species); share species;
global '(rates); share rates;
put('reac2ode,'psopfn,'r2oeval);
symbolic procedure r2oeval u;
begin scalar r,k,x,rhs,lhs,ratel,odel,oldorder,lhsl,rhsl;
integer rc;
if eqcar(species,'list) then
odel:=for each x in cdr species collect reval x . 0;
u := reval car u;
if not eqcar(u,'list) then typerr(u,"list of reactions");
u := cdr u;
loop:
if null u then goto finis;
r := reval car u; u := cdr u;
if not pairp r or not memq(car r,'(rightarrow doublearrow))
then goto synerror;
lhs := r2speclist cadr r;
rhs := r2speclist caddr r;
% include new species
for each x in append(lhs,rhs) do
odel:=r2oaddspecies(cdr x,odel);
% generate contribution from forward reaction.
k := if u and (x:=reval car u) and
not(pairp x and memq(car x,'(rightarrow doublearrow)))
then <<u:=cdr u; x>> else list('rate,rc:=rc+1);
ratel := k . ratel;
r2oreaction(lhs,rhs,k,odel);
% eventually generate backward reaction
if car r='doublearrow then
<<k := if u and (x:=reval car u) and
not(pairp x and memq(car x,'(rightarrow doublearrow)))
then <<u:=cdr u; x>> else list('rate,rc:=rc+1);
ratel := k . ratel;
r2oreaction(rhs,lhs,k,odel);
>>;
lhsl := lhs.lhsl; rhsl := rhs.rhsl;
goto loop;
finis:
ratel := reversip ratel;
rates := 'list. ratel;
for each x in ratel do
if numberp x or pairp x and get(car x,'dname) then
ratel := delete(x,ratel);
species := 'list. for each x in odel collect car x;
r2omat(cdr species,reversip lhsl,reversip rhsl);
for each r in ratel do if not idp r then
ratel:=delete(r,ratel);
if ratel then eval list('order,mkquote ratel);
oldorder := setkorder append(ratel,cdr species);
odel := 'list .
for each x in odel collect
list('equal,list('df,car x,'t),reval cdr x);
setkorder oldorder;
return odel;
synerror:
typerr(r,"reaction");
end;
symbolic procedure r2omat(sp,lhsl,rhsl);
% construct input and output matrices in REDUCE syntax.
begin scalar m; integer nreac,nspec,j;
nspec := length sp; nreac:= length lhsl;
apply ('matrix,list list list('inputmat,nreac,nspec));
apply ('matrix,list list list('outputmat,nreac,nspec));
for i:=1:nreac do
<< for each x in nth(lhsl,i) do
<<j:=r2findindex(cdr x,sp);
setmatelem(list ('inputmat,i,j),car x);
>>;
for each x in nth(rhsl,i) do
<<j:=r2findindex(cdr x,sp);
setmatelem(list ('outputmat,i,j),car x);
>>;
>>;
end;
symbolic procedure r2findindex(a,l); r2findindex1(a,l,1);
symbolic procedure r2findindex1(a,l,n);
if null l then rederr "index not found" else
if a=car l then n else r2findindex1(a,cdr l,n+1);
symbolic procedure r2speclist u;
% convert lhs/rhs to a list of pairs (multiplicity . spec).
<<u:=if eqcar(u,'plus) then cdr u else list u;
for each x in u collect r2speclist1 x>>;
symbolic procedure r2speclist1 x;
if eqcar(x,'times) then r2speclist2(cadr x,caddr x,cdddr x)
else 1 . x;
symbolic procedure r2speclist2(x1,x2,rst);
if not null rst or not fixp x1 and not fixp x2 then
typerr(append(list('times,x1,x2),rst),"species") else
if fixp x1 then x1.x2 else x2.x1;
symbolic procedure r2oaddspecies(s,odel);
% generate a new (empty) equation for a new species.
if assoc(s,odel) then odel else
<<prin2 "new species: ";prin2t s;
append(odel,list(s.0))>>;
symbolic procedure r2oreaction(lhs,rhs,k,odel);
% add the contribution of one reaction to the ode's.
begin scalar coeff,e;
coeff := k;
for each x in lhs do
coeff:=aeval list('times,coeff,list('expt,cdr x,car x));
for each x in lhs do
<<e := assoc(cdr x,odel);
rplacd(e,reval list('difference,cdr e,list('times,coeff,car x)))
>>;
for each x in rhs do
<<e := assoc(cdr x,odel);
rplacd(e,reval list('plus,cdr e,list('times,coeff,car x)))
>>;
return odel;
end;
endmodule;
end;