unit gibbs;

{$mode objfpc}{$H+}

interface
uses  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
   Buttons, ComCtrls, Menus, ExtCtrls, StdCtrls,Grids,pivotgauss,Math,UnitScaleFont,LCLType;
 const
 max_type_atomes=100;
 max_especes=100;
 constante_gaz_parfaits=8.314;
  a_debye=0.5091;
  b_debye=3.286;
  rtfln10=0.05915;
 type
 _tableau_nombres_atomes=tableaureel;
 _tableau_nombre_atomes_par_espece=matriceentiere;
 _nombre_atomes_par_espece=tableauentier;
 _nombres_moles=tableaureel;
 _tableau_noms_especes=tableaustring;
 _tableau_noms_atomes=tableaustring;
 _tableau_presents=tableaubooleen;


function calcule_equilibre_phase_gaz(nombres_especes,nombre_type_atomes:integer;
t_n_a:_tableau_nombres_atomes;  t_n_a_p_e:_tableau_nombre_atomes_par_espece;
var nombres_moles_equilibre: _nombres_moles;
potentiels_chimiques_standards:_nombres_moles;
pression,temperature,residu_max:float;max_iter:integer; var iter:integer):boolean;


 function calcule_equilibre_phase_aqueuse_annexe(nombre_solutes,nombre_precipites,nombre_type_atomes:integer;
 nombre_initial_moles_solvant:float;
tableau_nombre_initial_moles_solutes,tableau_nombre_initial_moles_precipites:_tableau_nombres_atomes;
moles_initiales_atomes:tableaureel;
t_n_a_p_e_solvant_1:tableaureel;
 t_n_a_p_e_solutes_1,t_n_a_p_e_precipites_1:matricereelle;
 nom_solvant:string;
 noms_solutes,noms_precipites:tableaustring;
 var nombre_moles_equilibre_solvant:float;
var nombre_moles_equilibre_solutes,nombre_moles_equilibre_precipites,
activites_solutes: _nombres_moles;
potentiel_chimique_standard_solvant:float;
potentiels_chimiques_standards_solutes,potentiels_chimiques_standards_precipites,rayons_solutes:_nombres_moles;
volume,temperature,maxresiduconservationrelatif,
maxresiduactionmasserelatif:float;
max_iter:integer; var iter:integer;
var enthalpie_libre:float;
debye:boolean):boolean;

function calcule_equilibre_solution_aqueuse_avec_precipites(nombre_solutes,nombre_precipites,nombre_type_atomes:integer;
nombre_initial_moles_solvant:float;
tableau_nombre_initial_moles_solutes,tableau_nombre_initial_moles_precipites:_tableau_nombres_atomes;
 t_n_a_p_e_solvant:tableaureel;
 t_n_a_p_e_solutes,t_n_a_p_e_precipites:matricereelle;
 nom_solvant:string;
 noms_solutes,noms_precipites:tableaustring;
 var nombre_moles_equilibre_solvant:float;
var nombre_moles_equilibre_solutes,nombre_moles_equilibre_precipites,
activites_solutes: _nombres_moles;
potentiel_chimique_standard_solvant:float;
potentiels_chimiques_standards_solutes,potentiels_chimiques_standards_precipites,
rayons_solutes:_nombres_moles;
volume,temperature,maxresiduconservationrelatif,
maxresiduactionmasserelatif:float;max_iter:integer; var iter:integer;
var enthalpie_libre:float;
debye:boolean):boolean;



function puissance_entiere(base,exposant:integer):longint;

function minabstableauhorszero(t:tableaureel; n:integer):float;
function minabs(a,b:float):float;
function maxabs(a,b:float):float;
function maxabstableau(t:tableaureel; n:integer):float;
function minabstableauhorstroppetit(t:tableaureel; n:integer; seuil_significatif:float):float;
var
pluspetiteconcentrationsignificative, pluspetitlnconcentrationsignificatif:float;
implementation

uses UnitGaussJordan,Unit1,Unit2;

function maxabstableau(t:tableaureel; n:integer):float;
var i:integer; mama:float;
begin
if n<=0 then begin
  result:=0;
  exit;
  end;

  if n=1 then begin
  result:=abs(t[0]);
  exit;
  end;

 mama:=abs(t[0]);
 for i:=2 to n do
 mama:=maxabs(mama,t[i-1]);
 result:=mama;
     end;

function minabs(a,b:float):float;
begin
if abs(a)<abs(b) then result:=abs(a) else
result:=abs(b);
end;

function maxabs(a,b:float):float;
begin
if abs(a)>abs(b) then result:=abs(a) else
result:=abs(b);
end;

 function minabstableauhorszero(t:tableaureel; n:integer):float;
  var i,j:integer; mimi:float;
  begin
  if n<=0 then begin
  result:=0;
  exit;
  end;

  if n=1 then begin
  result:=abs(t[0]);
  exit;
  end;

  i:=0;
  repeat
  inc(i);
  mimi:=abs(t[i-1]);
  until ((mimi<>0) or (i=n));

  if i=n then begin
  result:=mimi;
 exit;
 end;

   for j:=i+1 to n do
   if t[j-1]<>0 then
   mimi:=minabs(mimi,t[j-1]);
   result:=mimi;
   end;

function minabstableauhorstroppetit(t:tableaureel; n:integer; seuil_significatif:float):float;
 var i,j:integer; mimi:float;
  begin
  if n<=0 then begin
  result:=0;
  exit;
  end;

  if n=1 then begin
  result:=abs(t[0]);
  exit;
  end;

  i:=0;
  repeat
  inc(i);
  mimi:=abs(t[i-1]);
  until ((mimi>abs(seuil_significatif)) or (i=n));

  if i=n then begin
  result:=mimi;
 exit;
 end;

   for j:=i+1 to n do
   if abs(t[j-1])>=abs(seuil_significatif) then
   mimi:=minabs(mimi,t[j-1]);
   result:=mimi;
   end;




function puissance_entiere(base,exposant:integer):longint;
var i:integer; res:longint;
begin
res:=1;
if exposant>0 then
for i:=1 to exposant do res:=res*base;
puissance_entiere:=res;
end;



function calcule_equilibre_phase_gaz(nombres_especes,nombre_type_atomes:integer;
t_n_a:_tableau_nombres_atomes;  t_n_a_p_e:_tableau_nombre_atomes_par_espece;
var nombres_moles_equilibre: _nombres_moles;
potentiels_chimiques_standards:_nombres_moles;
pression,temperature,residu_max:float;max_iter:integer; var iter:integer):boolean;
 {pression en bar, temperature en K}

var nombre_moles_gaz:float;
i,j,k:integer;
potentiels_chimiques:_nombres_moles;
 mat:matricereelle;
 delta,delt:tableaureel;
 inter1,inter2,fac1,fac2,fac,residu:float;
begin
setlength(potentiels_chimiques,nombres_especes);
setlength(mat,nombre_type_atomes+1,nombre_type_atomes+2);
setlength(delta,nombres_especes+1);
setlength(delt,nombre_type_atomes+1);
 nombre_moles_gaz:=0.1;
   for j:=1 to nombres_especes do  nombres_moles_equilibre[j-1]:=0.1/nombres_especes;
     iter:=0;

   REPEAT
   inc(iter);
   for j:=1 to nombres_especes do
    potentiels_chimiques[j-1]:= potentiels_chimiques_standards[j-1]+
    constante_gaz_parfaits*temperature*ln(nombres_moles_equilibre[j-1]/nombre_moles_gaz*pression);

    for k:=1 to nombre_type_atomes do begin
    inter1:=0;
    for j:=1 to nombres_especes do inter1:=inter1+t_n_a_p_e[k-1,j-1]*nombres_moles_equilibre[j-1]*
    (potentiels_chimiques[j-1]/constante_gaz_parfaits/temperature-1);
        mat[k,nombre_type_atomes+1]:=t_n_a[k-1]+inter1;
    for i:=1 to  nombre_type_atomes do begin
    inter2:=0;
    for j:=1 to  nombres_especes do inter2:=inter2+ t_n_a_p_e[k-1,j-1]*t_n_a_p_e[i-1,j-1]*
     nombres_moles_equilibre[j-1];
     mat[k-1,i-1]:=inter2;
     end;
     inter1:=0;
     for j:=1 to  nombres_especes do inter1:=inter1+ t_n_a_p_e[k-1,j-1]*
     nombres_moles_equilibre[j-1];
     mat[k-1,nombre_type_atomes]:=inter1;
     end;


     inter1:=0;
     for j:=1 to   nombres_especes do
     inter1:=inter1+nombres_moles_equilibre[j-1]*(potentiels_chimiques[j-1]/constante_gaz_parfaits/temperature-1);
     mat[nombre_type_atomes,nombre_type_atomes+1]:=nombre_moles_gaz+inter1;
     for i:=1 to  nombre_type_atomes do begin
    inter2:=0;
    for j:=1 to  nombres_especes do inter2:=inter2+ t_n_a_p_e[i-1,j-1]*
     nombres_moles_equilibre[j-1];
     mat[nombre_type_atomes,i-1]:=inter2;
     end;
     inter1:=0;
     for j:=1 to  nombres_especes do inter1:=inter1+ nombres_moles_equilibre[j-1];
     mat[nombre_type_atomes,nombre_type_atomes]:=inter1-nombre_moles_gaz;

     ResoudLineaire(mat,nombre_type_atomes+1,delt);

     for j:=1 to nombres_especes do begin
     inter1:=0;
     for i:=1 to  nombre_type_atomes do inter1:=inter1+ t_n_a_p_e[i-1,j-1]*delt[i-1];
     delta[j-1]:=delt[nombre_type_atomes]+inter1-potentiels_chimiques[j-1]/constante_gaz_parfaits/temperature;
     end;

     delta[nombres_especes]:=delt[nombre_type_atomes];

     fac1:=5*abs( delta[nombres_especes]);
     for j:=1 to nombres_especes do
     if abs(delta[j-1])>fac1 then fac1:=abs(delta[j-1]);
     fac1:=2/fac1;

     fac2:=1;
     for j:=1 to  nombres_especes do
     if  ((nombres_moles_equilibre[j-1]<1e-8*nombre_moles_gaz) and
     (delta[j-1]>0) and
     (abs((-ln(nombres_moles_equilibre[j-1]/nombre_moles_gaz)-9.2103404)/
     (delta[j-1]-delta[nombres_especes]))<fac2)) then
     fac2:=abs((-ln(nombres_moles_equilibre[j-1]/nombre_moles_gaz)-9.2103404)/
     (delta[j-1]-delta[nombres_especes]));

     fac:=1;
     if fac1<fac then fac:=fac1;
     if fac2<fac then fac:=fac2;

     for j:=1 to nombres_especes do
      nombres_moles_equilibre[j-1]:=nombres_moles_equilibre[j-1]*exp(fac*delta[j-1]);
      nombre_moles_gaz:=nombre_moles_gaz*exp(fac*delta[nombres_especes]);


      inter1:=0;
   for j:=1 to nombres_especes do
   inter1:=inter1+t_n_a_p_e[0,j-1]*nombres_moles_equilibre[j-1];
   inter1:=abs(inter1-t_n_a[0])/t_n_a[0];
   residu:=inter1;

   if nombre_type_atomes>1 then
   for k:=2 to  nombre_type_atomes do begin
   inter1:=0;
   for j:=1 to nombres_especes do
   inter1:=inter1+t_n_a_p_e[k-1,j-1]*nombres_moles_equilibre[j-1];
   inter1:=abs(inter1-t_n_a[k-1])/t_n_a[k-1];
   if inter1>residu then residu:=inter1;
   end;



   UNTIL   ((residu<residu_max) or (iter>max_iter));

    calcule_equilibre_phase_gaz:=(iter<=max_iter);
   finalize(potentiels_chimiques);
finalize(mat);
finalize(delta);
finalize(delt);


     end;




   function calcule_equilibre_phase_aqueuse_annexe(nombre_solutes,nombre_precipites,nombre_type_atomes:integer;
   nombre_initial_moles_solvant:float;
tableau_nombre_initial_moles_solutes,tableau_nombre_initial_moles_precipites:_tableau_nombres_atomes;
moles_initiales_atomes:tableaureel;
t_n_a_p_e_solvant_1:tableaureel;
 t_n_a_p_e_solutes_1,t_n_a_p_e_precipites_1:matricereelle;
 nom_solvant:string;
 noms_solutes,noms_precipites:tableaustring;
 var nombre_moles_equilibre_solvant:float;
var nombre_moles_equilibre_solutes,nombre_moles_equilibre_precipites,
activites_solutes: _nombres_moles;
potentiel_chimique_standard_solvant:float;
potentiels_chimiques_standards_solutes,potentiels_chimiques_standards_precipites,
rayons_solutes:_nombres_moles;
volume,temperature,maxresiduconservationrelatif,
maxresiduactionmasserelatif:float;
max_iter:integer; var iter:integer;
var enthalpie_libre:float;
debye:boolean):boolean;
 {pression en bar, temperature en K}

var
i,j,k,kkk,rang,reac:integer;
potentiels_chimiques_precipites,potentiels_chimiques_solutes,t_n_a:_nombres_moles;
delta_solvant,potentiel_chimique_solvant,nombre_total_hors_solvant,nombre_total_moles_solutes,delta_charge:float;
 mat,a,aa,coeff_stoechio:matricereelle;
 delta_ln_solutes,delta_precipites,delt,delt_old,b,bb,potentiel_standard,deltarg0,lk:tableaureel;
 inter1,inter2,fac1,fac2,fac,plusgrandelement:float;
 testadditionnel,test_precipites,test_solutes:boolean;
 f:textfile;
 noms_1,f_b_1,reactions,equations_conservation,equations_avancements,ea:tableaustring;
 t_n_a_p_e_solvant,nono_1:tableaureel;
 t_n_a_p_e_solutes,t_n_a_p_e_precipites:matricereelle;
 plusgrandresiduactionmasserelatif,plusgrandresiduconservationrelatif:float;
 residuconservationrelatif,residuconservation,residuactionmasserelatif,
 residuactionmasse,tata:tableaureel;
  un_seul_non_nul,tous_nuls:boolean;
  moles_initiales_atomes_0,nombre_moles_equilibre_precipites_p_p:tableaureel;
correspondance_atomes,correspondance_solutes,correspondance_precipites:array of integer;
   atomes_de_concentration_nulle,solutes_de_concentration_bloquee,
   precipites_de_concentration_bloquee:array of boolean;
   nombre_type_atomes_p0,nombre_solutes_p0,nombre_precipites_p0:integer;
   t_n_a_p_e_solvant_p0:tableaureel;
 t_n_a_p_e_solutes_p0,t_n_a_p_e_precipites_p0:matricereelle;
 tableau_nombre_initial_moles_solutes_p0,tableau_nombre_initial_moles_precipites_p0:
 _tableau_nombres_atomes;
 noms_solutes_p0,noms_precipites_p0:tableaustring;
 potentiels_chimiques_standards_solutes_p0,potentiels_chimiques_standards_precipites_p0,
 charges_solutes_p0,rayons_solutes_p0:
  _tableau_nombres_atomes;
  moles_initiales_atomes_0_p0:tableaureel;
  nombre_moles_equilibre_solutes_p0,nombre_moles_equilibre_precipites_p0:_nombres_moles;
  reactions_bloquees:array of boolean;
  bloblo:boolean;  totalll:float;
  force_ionique,force_ionique_partie_constante:float;
 begin
 setlength(nombre_moles_equilibre_solutes,nombre_solutes);
 setlength(nombre_moles_equilibre_precipites,nombre_precipites);


 {on refait le compte des nombres d'atome, pour verifier s'il n'y a pas d'erreur
    dans les donnees (cas par exemple d'une precipite non compte alors qu'il est
    present initialement)}
   { for i:=1 to nombre_type_atomes do begin
    totalll:=0;
    if nombre_solutes>0 then
    for j:=1 to nombre_solutes do
    totalll:=totalll+tableau_nombre_initial_moles_solutes[j-1]*
    t_n_a_p_e_solutes_1[i-1,j-1];
    if nombre_precipites>0 then
    for j:=1 to nombre_precipites do
    totalll:=totalll+tableau_nombre_initial_moles_precipites[j-1]*
    t_n_a_p_e_precipites_1[i-1,j-1];
     totalll:=totalll+nombre_initial_moles_solvant*
    t_n_a_p_e_solvant_1[i-1];
    if abs(abs(totalll)-abs(moles_initiales_atomes[i-1]))>
    max(abs(totalll),abs(moles_initiales_atomes[i-1]))*1e-10
    then begin
    result:=false;
    exit;
    end;
    end;}


 {on fabrique les matrices necessaires pour determiner les equations de
 conservation independante}
 setlength(a,nombre_type_atomes,1+nombre_solutes+nombre_precipites);
 setlength(b,nombre_type_atomes);
 for i:=1 to nombre_type_atomes do
 a[i-1,0]:=t_n_a_p_e_solvant_1[i-1];
 if nombre_solutes>0 then
  for i:=1 to nombre_type_atomes do
  for j:=1 to nombre_solutes do
  a[i-1,j-1+1]:=t_n_a_p_e_solutes_1[i-1,j-1];
  if nombre_precipites>0 then
  for i:=1 to nombre_type_atomes do
  for j:=1 to nombre_precipites do
  a[i-1,j-1+1+nombre_solutes]:=t_n_a_p_e_precipites_1[i-1,j-1];

   for i:=1 to nombre_type_atomes do
   b[i-1]:=moles_initiales_atomes[i-1];

 setlength(noms_1,1+nombre_solutes+nombre_precipites);
 setlength( f_b_1,1+nombre_solutes+nombre_precipites);
 noms_1[0]:=nom_solvant;
  f_b_1[0]:=nom_solvant;
  if nombre_solutes>0 then
  for i:=1 to nombre_solutes do begin
  noms_1[i]:=noms_solutes[i-1];
    f_b_1[i]:=noms_solutes[i-1]; end;
  if nombre_precipites>0 then
  for i:=1 to nombre_precipites do begin
  noms_1[i+nombre_solutes]:=noms_precipites[i-1];
    f_b_1[i+nombre_solutes]:=noms_precipites[i-1]; end;


 setlength(potentiel_standard,1+nombre_solutes+nombre_precipites);
  potentiel_standard[0]:=potentiel_chimique_standard_solvant;
 if nombre_solutes>0 then
  for i:=1 to nombre_solutes do
  potentiel_standard[i]:=potentiels_chimiques_standards_solutes[i-1];
  if nombre_precipites>0 then
  for i:=1 to nombre_precipites do
  potentiel_standard[i+nombre_solutes]:=potentiels_chimiques_standards_precipites[i-1];


 DetermineReactionsAnnexe(a,moles_initiales_atomes,1+nombre_solutes+nombre_precipites,nombre_type_atomes,
noms_1,f_b_1,rang,reac,reactions,equations_conservation,
aa,bb,coeff_stoechio,potentiel_standard,deltarG0,temperature);




{s'il n'y a pas de reactions}
if reac=0 then begin
 setlength(potentiels_chimiques_precipites,nombre_precipites);
 setlength(potentiels_chimiques_solutes,nombre_solutes);
 setlength(activites_solutes,nombre_solutes);
nombre_moles_equilibre_solvant:=nombre_initial_moles_solvant;
if nombre_solutes>0 then for i:=1 to nombre_solutes do
nombre_moles_equilibre_solutes[i-1]:=
tableau_nombre_initial_moles_solutes[i-1];
if nombre_precipites>0 then for i:=1 to nombre_precipites do
nombre_moles_equilibre_precipites[i-1]:=
tableau_nombre_initial_moles_precipites[i-1];
  force_ionique:=0;
 for i:=1 to nombre_solutes do
   force_ionique:=force_ionique+0.5*sqr(charges_solutes_0[i-1])*
   nombre_moles_equilibre_solutes[i-1]/volume;

if not(debye) then
if nombre_solutes>0 then for i:=1 to nombre_solutes do
activites_solutes[i-1]:=
tableau_nombre_initial_moles_solutes[i-1]/volume;

if debye then
if nombre_solutes>0 then
   for j:=1 to nombre_solutes do
   if nombre_moles_equilibre_solutes[j-1]>0 then begin
    potentiels_chimiques_solutes[j-1]:= potentiels_chimiques_standards_solutes[j-1]+
    constante_gaz_parfaits*temperature*(
    ln(nombre_moles_equilibre_solutes[j-1]/volume)-
    ln(10)*a_debye*sqr(charges_solutes_0[j-1])*sqrt(force_ionique)/
    (1+b_debye*rayons_solutes_0[j-1]*sqrt(force_ionique)));
    activites_solutes[j-1]:=exp(
    ln(nombre_moles_equilibre_solutes[j-1]/volume)-
    ln(10)*a_debye*sqr(charges_solutes_0[j-1])*sqrt(force_ionique)/
    (1+b_debye*rayons_solutes[j-1]*sqrt(force_ionique)));
    enthalpie_libre:=enthalpie_libre+
    nombre_moles_equilibre_solutes[j-1]*potentiels_chimiques_solutes[j-1];
     end else  activites_solutes[j-1]:=0;

   if debye then
 if nombre_solutes>0 then
   for j:=1 to nombre_solutes do
   if nombre_moles_equilibre_solutes[j-1]<>0 then
    potentiels_chimiques_solutes[j-1]:= potentiels_chimiques_standards_solutes[j-1]+
    constante_gaz_parfaits*temperature*ln(nombre_moles_equilibre_solutes[j-1]/volume)
    else potentiels_chimiques_solutes[j-1]:=0;
 if nombre_precipites>0 then
   for j:=1 to nombre_precipites do
   if nombre_moles_equilibre_precipites[j-1]<>0 then
   potentiels_chimiques_precipites[j-1]:=potentiels_chimiques_standards_precipites[j-1]
   else potentiels_chimiques_precipites[j-1]:=0;
 potentiel_chimique_solvant:=potentiel_chimique_standard_solvant;

  enthalpie_libre:=nombre_moles_equilibre_solvant*potentiel_chimique_solvant;

     if nombre_precipites>0 then
     for i:=1 to nombre_precipites do
enthalpie_libre:=enthalpie_libre+nombre_moles_equilibre_precipites[i-1]*potentiels_chimiques_precipites[i-1];

      if nombre_solutes>0 then
   for j:=1 to nombre_solutes do
     enthalpie_libre:=enthalpie_libre+nombre_moles_equilibre_solutes[j-1]*potentiels_chimiques_solutes[j-1];
 iter:=0;
 result:=true;
 exit;
 end;

 {du cas ou il n'y a pas de reaction}


      {on regarde s'il y a des nombre de moles d'atome nuls, ce qui
 permet d'eliminer des especes}

 setlength(correspondance_solutes,nombre_solutes);
 setlength(correspondance_precipites,nombre_precipites);
   setlength(atomes_de_concentration_nulle,nombre_type_atomes);
   setlength(solutes_de_concentration_bloquee,nombre_solutes);
   setlength(precipites_de_concentration_bloquee,nombre_precipites);
  {on repere les atomes en nombre nul}
   for i:=1 to   nombre_type_atomes
   do  if ensemble_atomes[i-1]<>-1 then
   atomes_de_concentration_nulle[i-1]:=(moles_initiales_atomes[i-1]=0) else
   atomes_de_concentration_nulle[i-1]:=false;
   {on en deduit les solutes en nombre nul}
    if nombre_solutes>0 then      for i:=1 to   nombre_solutes do begin
     solutes_de_concentration_bloquee[i-1]:=false;
     for j:=1 to  nombre_type_atomes do  if  atomes_de_concentration_nulle[j-1]
     then if   t_n_a_p_e_solutes_1[j-1,i-1]<>0 then
       solutes_de_concentration_bloquee[i-1]:=true;
        end;
        {si un solute ne figure dans aucune reaction, sa concentration
        est imposee a sa valeur initiale}
    if nombre_solutes>0 then      for i:=1 to   nombre_solutes do begin
     bloblo:=true;
     for j:=1 to reac do
     bloblo:=bloblo and
      (coeff_stoechio[j-1,i]=0);
       solutes_de_concentration_bloquee[i-1]:=bloblo or
       solutes_de_concentration_bloquee[i-1] ;
        end;
    {et les precipites en nombre nul}
    if nombre_precipites>0 then      for i:=1 to   nombre_precipites do begin
     precipites_de_concentration_bloquee[i-1]:=false;
     for j:=1 to  nombre_type_atomes do  if  atomes_de_concentration_nulle[j-1]
     then if   t_n_a_p_e_precipites_1[j-1,i-1]<>0 then
       precipites_de_concentration_bloquee[i-1]:=true;
        end;
        {si un precipite ne figure dans aucune reaction, sa concentration
        est imposee a sa valeur initiale}
    if nombre_precipites>0 then      for i:=1 to   nombre_precipites do begin
     bloblo:=true;
     for j:=1 to reac do
     bloblo:=bloblo and
      (coeff_stoechio[j-1,i+nombre_solutes]=0);
       precipites_de_concentration_bloquee[i-1]:=bloblo or
       precipites_de_concentration_bloquee[i-1] ;
        end;
        {on repere les reactions bloquees}
        setlength(reactions_bloquees,reac);
        for i:=1 to reac do  reactions_bloquees[i-1]:=false;
          for i:=1 to reac do  begin
          for j:=1 to nombre_solutes do
          if  ((coeff_stoechio[i-1,j]<>0) and  solutes_de_concentration_bloquee[j-1])
          then   reactions_bloquees[i-1]:=true;
           for j:=1 to nombre_precipites do
          if  ((coeff_stoechio[i-1,j+nombre_solutes]<>0) and
          precipites_de_concentration_bloquee[j-1])
          then   reactions_bloquees[i-1]:=true;
            end;

         {pour chaque espece, on cherche si elle n'apparait pas
         uniquement dans des reactions bloquees, auquel cas sa
         concentration est bloquee a sa valeur initiale}
         if nombre_solutes>0 then
         for i:=1 to nombre_solutes do begin
         bloblo:=true;
         for j:=1 to reac do
         if ((coeff_stoechio[j-1,i]<>0)   and not(reactions_bloquees[j-1]))
        then bloblo:=false;
         solutes_de_concentration_bloquee[i-1]:=
         solutes_de_concentration_bloquee[i-1] or bloblo;
         end;

           if nombre_precipites>0 then
          for i:=1 to nombre_precipites do begin
         bloblo:=true;
         for j:=1 to reac do
        if ((coeff_stoechio[j-1,i+nombre_solutes]<>0) and not(reactions_bloquees[j-1]))
        then bloblo:=false;
         precipites_de_concentration_bloquee[i-1]:=
         precipites_de_concentration_bloquee[i-1] or bloblo;
         end;
         {maintenant qu'on connait toutes les especes bloquees, on complete
         les atomes a ne pas prendre en commpte}
         for i:=1 to nombre_type_atomes do
         if ensemble_atomes[i-1]<>-1 then begin
         bloblo:=true;
         for j:=1 to nombre_solutes do
         if  ((t_n_a_p_e_solutes_1[i-1,j-1]<>0) and
         not(solutes_de_concentration_bloquee[j-1])) then
         bloblo:=false;
         for j:=1 to nombre_precipites do
         if  ((t_n_a_p_e_precipites_1[i-1,j-1]<>0) and
         not(precipites_de_concentration_bloquee[j-1])) then
         bloblo:=false;
         atomes_de_concentration_nulle[i-1]:=atomes_de_concentration_nulle[i-1]
         or bloblo;
         end;

        {on compte les atomes en nombre nul et on fait les correspondances}
        nombre_type_atomes_p0:=0;
        for i:=1 to nombre_type_atomes do
        if not(atomes_de_concentration_nulle[i-1]) then begin
        inc(nombre_type_atomes_p0);
       setlength(correspondance_atomes,nombre_type_atomes_p0);
         correspondance_atomes[nombre_type_atomes_p0-1]:=i;
         end;
         setlength(moles_initiales_atomes_0_p0,nombre_type_atomes_p0);
         for i:=1 to nombre_type_atomes_p0 do
         moles_initiales_atomes_0_p0[i-1]:=
         moles_initiales_atomes[correspondance_atomes[i-1]-1];
         {on recalcule la charge totale eventuelle}
         i:=0;
         repeat
         inc(i);
         until ((i=nombre_type_atomes) or  (ensemble_atomes[i-1]=-1));
         if (ensemble_atomes[i-1]=-1) then begin
          j:=0;
          repeat inc(j);
          until  correspondance_atomes[j-1]=i;
          moles_initiales_atomes_0_p0[j-1]:=0;
          for k:=1 to nombre_solutes do
          if  not(solutes_de_concentration_bloquee[k-1]) then
          moles_initiales_atomes_0_p0[j-1]:=moles_initiales_atomes_0_p0[j-1]+
          t_n_a_p_e_solutes_1[i-1,k-1]*tableau_nombre_initial_moles_solutes[k-1];
          end;

          force_ionique_partie_constante:=0;
    {on compte les solutes de concentration nulle et on fait le tableau des correspondances}
    nombre_solutes_p0:=0;
    for i:=1 to nombre_solutes do if  not(solutes_de_concentration_bloquee[i-1]) then begin
    inc(nombre_solutes_p0);
    setlength(correspondance_solutes,nombre_solutes_p0);
         correspondance_solutes[nombre_solutes_p0-1]:=i;
         end else
         force_ionique_partie_constante:=force_ionique_partie_constante
         +0.5*sqr(charges_solutes_0[i-1])*tableau_nombre_initial_moles_solutes[i-1]/volume;


    {on compte les precipites de concentration nulle et on fait le tableau des correspondances}
    nombre_precipites_p0:=0;
    for i:=1 to nombre_precipites do if  not(precipites_de_concentration_bloquee[i-1]) then begin
    inc(nombre_precipites_p0);
    setlength(correspondance_precipites,nombre_precipites_p0);
         correspondance_precipites[nombre_precipites_p0-1]:=i;
         end;
         {correspondance pour le solvant}
         setlength(t_n_a_p_e_solvant_p0,nombre_type_atomes_p0);
         for i:=1 to nombre_type_atomes_p0 do
       t_n_a_p_e_solvant_p0[i-1]:=t_n_a_p_e_solvant_1[correspondance_atomes[i-1]-1];
    {on fait le nouveau tableau des concentrations initiales et les tnape pour les solutes}
    setlength(tableau_nombre_initial_moles_solutes_p0,nombre_solutes_p0);
    setlength(t_n_a_p_e_solutes_p0,nombre_type_atomes_p0,nombre_solutes_p0);
    for i:=1 to  nombre_solutes_p0 do begin
   tableau_nombre_initial_moles_solutes_p0[i-1]:=
   tableau_nombre_initial_moles_solutes[correspondance_solutes[i-1]-1];
   for j:=1 to nombre_type_atomes_p0 do
  t_n_a_p_e_solutes_p0[j-1,i-1]:=
  t_n_a_p_e_solutes_1[correspondance_atomes[j-1]-1,
    correspondance_solutes[i-1]-1];
    end;
    {on fait le nouveau tableau des concentrations initiales et les tnape pour les precipites}
    setlength(tableau_nombre_initial_moles_precipites_p0,nombre_precipites_p0);
    setlength(t_n_a_p_e_precipites_p0,nombre_type_atomes_p0,nombre_precipites_p0);
    for i:=1 to  nombre_precipites_p0 do begin
   tableau_nombre_initial_moles_precipites_p0[i-1]:=
   tableau_nombre_initial_moles_precipites[correspondance_precipites[i-1]-1];
   for j:=1 to nombre_type_atomes_p0 do
  t_n_a_p_e_precipites_p0[j-1,i-1]:=
  t_n_a_p_e_precipites_1[correspondance_atomes[j-1]-1,
    correspondance_precipites[i-1]-1];
    end;
   {nouveau tableau des noms et des potentiels}
   setlength(noms_solutes_p0,nombre_solutes_p0);
   setlength(charges_solutes_p0,nombre_solutes_p0);
     setlength(rayons_solutes_p0,nombre_solutes_p0);
   setlength(potentiels_chimiques_standards_solutes_p0,nombre_solutes_p0);
  setlength(potentiels_chimiques_standards_precipites_p0,nombre_precipites_p0);
   setlength(noms_precipites_p0,nombre_precipites_p0);
    for i:=1 to  nombre_solutes_p0 do begin
   noms_solutes_p0[i-1]:=noms_solutes[correspondance_solutes[i-1]-1];
   charges_solutes_p0[i-1]:=charges_solutes_0[correspondance_solutes[i-1]-1];
    rayons_solutes_p0[i-1]:=rayons_solutes_0[correspondance_solutes[i-1]-1];
   potentiels_chimiques_standards_solutes_p0[i-1]:=
   potentiels_chimiques_standards_solutes[correspondance_solutes[i-1]-1];
   end;
   for i:=1 to  nombre_precipites_p0 do begin
   noms_precipites_p0[i-1]:=noms_precipites[correspondance_precipites[i-1]-1];
   potentiels_chimiques_standards_precipites_p0[i-1]:=
   potentiels_chimiques_standards_precipites[correspondance_precipites[i-1]-1];
   end;


    {on recommence la determination du rang}
   setlength(nombre_moles_equilibre_solutes,nombre_solutes_p0);
 setlength(nombre_moles_equilibre_precipites,nombre_precipites_p0);
 {on fabrique les matrices necessaires pour determiner les equations de
 conservation independante}
 setlength(a,nombre_type_atomes_p0,1+nombre_solutes_p0+nombre_precipites_p0);
 setlength(b,nombre_type_atomes_p0);
 for i:=1 to nombre_type_atomes_p0 do
 a[i-1,0]:=t_n_a_p_e_solvant_p0[i-1];
 if nombre_solutes_p0>0 then
  for i:=1 to nombre_type_atomes_p0 do
  for j:=1 to nombre_solutes_p0 do
  a[i-1,j-1+1]:=t_n_a_p_e_solutes_p0[i-1,j-1];
  if nombre_precipites_p0>0 then
  for i:=1 to nombre_type_atomes_p0 do
  for j:=1 to nombre_precipites_p0 do
  a[i-1,j-1+1+nombre_solutes_p0]:=t_n_a_p_e_precipites_p0[i-1,j-1];

   for i:=1 to nombre_type_atomes_p0 do
   b[i-1]:=moles_initiales_atomes_0_p0[i-1];

 setlength(noms_1,1+nombre_solutes_p0+nombre_precipites_p0);
 setlength( f_b_1,1+nombre_solutes_p0+nombre_precipites_p0);
 setlength( nono_1,1+nombre_solutes_p0+nombre_precipites_p0);
 noms_1[0]:=nom_solvant;
  f_b_1[0]:=nom_solvant;
   nono_1[0]:=nombre_initial_moles_solvant;

  if nombre_solutes_p0>0 then
  for i:=1 to nombre_solutes_p0 do begin
  noms_1[i]:=noms_solutes_p0[i-1];
    f_b_1[i]:=noms_solutes_p0[i-1];
    nono_1[i]:=tableau_nombre_initial_moles_solutes_p0[i-1];
     end;
  if nombre_precipites_p0>0 then
  for i:=1 to nombre_precipites_p0 do begin
  noms_1[i+nombre_solutes_p0]:=noms_precipites_p0[i-1];
    f_b_1[i+nombre_solutes_p0]:=noms_precipites_p0[i-1];
    nono_1[i+nombre_solutes_p0]:=tableau_nombre_initial_moles_precipites_p0[i-1];
    end;


 setlength(potentiel_standard,1+nombre_solutes_p0+nombre_precipites_p0);
  potentiel_standard[0]:=potentiel_chimique_standard_solvant;
 if nombre_solutes_p0>0 then
  for i:=1 to nombre_solutes_p0 do
  potentiel_standard[i]:=potentiels_chimiques_standards_solutes_p0[i-1];
  if nombre_precipites_p0>0 then
  for i:=1 to nombre_precipites_p0 do
  potentiel_standard[i+nombre_solutes_p0]:=potentiels_chimiques_standards_precipites_p0[i-1];


   DetermineReactions(a,nono_1,
 1+nombre_solutes_p0+nombre_precipites_p0,nombre_type_atomes_p0,
noms_1,f_b_1,rang,reac,reactions,equations_conservation,ea,
aa,bb,coeff_stoechio,potentiel_standard,deltarG0,lk,temperature);
       finalize(ea); finalize(lk); finalize(nono_1);

 {DetermineReactionsAnnexe(a,moles_initiales_atomes_0_p0,
 1+nombre_solutes_p0+nombre_precipites_p0,nombre_type_atomes_p0,
noms_1,f_b_1,rang,reac,reactions,equations_conservation,
aa,bb,coeff_stoechio,potentiel_standard,deltarG0,temperature);}




 setlength(t_n_a_p_e_solvant,rang);
setlength(t_n_a_p_e_solutes,rang,nombre_solutes_p0);
setlength(t_n_a_p_e_precipites,rang,nombre_precipites_p0);
for i:=1 to rang do t_n_a_p_e_solvant[i-1]:=aa[i-1,0];
if nombre_solutes_p0>0 then for j:=1 to nombre_solutes_p0 do
for i:=1 to rang do t_n_a_p_e_solutes[i-1,j-1]:=aa[i-1,j];
if nombre_precipites_p0>0 then for j:=1 to nombre_precipites_p0 do
for i:=1 to rang do t_n_a_p_e_precipites[i-1,j-1]:=aa[i-1,j+nombre_solutes_p0];

 setlength(potentiels_chimiques_precipites,nombre_precipites_p0);
 setlength(potentiels_chimiques_solutes,nombre_solutes_p0);
 setlength(mat,rang+1+nombre_precipites_p0,
 rang+1+nombre_precipites_p0+1);
 setlength(delta_ln_solutes,nombre_solutes_p0);
 setlength(delta_precipites,nombre_precipites_p0);
 setlength(delt,rang+1+nombre_precipites_p0);
 setlength(delt_old,rang+1+nombre_precipites_p0);
 setlength(t_n_a,rang);


 {calcul du nombre d'atomes pour chaque atome}
 for k:=1 to rang do
  t_n_a[k-1]:=bb[k-1];


   nombre_moles_equilibre_solvant:=nombre_initial_moles_solvant;

 if nombre_solutes_p0>0 then
   for j:=1 to nombre_solutes_p0 do  nombre_moles_equilibre_solutes[j-1]:=0.1/nombre_solutes_p0;
     iter:=0;

 if nombre_precipites_p0>0 then
   for j:=1 to nombre_precipites_p0 do  begin
   nombre_moles_equilibre_precipites[j-1]:=0;
   potentiels_chimiques_precipites[j-1]:=potentiels_chimiques_standards_precipites_p0[j-1];
   end;

   potentiel_chimique_solvant:=potentiel_chimique_standard_solvant;

     iter:=0;

   REPEAT
   inc(iter);

   if nombre_solutes_p0>0 then
   for j:=1 to nombre_solutes_p0 do
    potentiels_chimiques_solutes[j-1]:= potentiels_chimiques_standards_solutes_p0[j-1]+
    constante_gaz_parfaits*temperature*ln(nombre_moles_equilibre_solutes[j-1]/volume);

    for k:=1 to rang do begin

    {calcul du seond membre des equations issues de la conservation
    de la matiere}
    inter1:=0;
    if nombre_solutes_p0>0 then
    for j:=1 to nombre_solutes_p0 do
    inter1:=inter1+t_n_a_p_e_solutes[k-1,j-1]*nombre_moles_equilibre_solutes[j-1]*
    (potentiels_chimiques_solutes[j-1]/constante_gaz_parfaits/temperature-1);
    inter1:=inter1-t_n_a_p_e_solvant[k-1]*nombre_moles_equilibre_solvant;
    if nombre_precipites_p0>0 then
    for j:=1 to nombre_precipites_p0 do
    inter1:=inter1-t_n_a_p_e_precipites[k-1,j-1]*nombre_moles_equilibre_precipites[j-1];

        mat[k-1,rang+2+nombre_precipites_p0-1]:=t_n_a[k-1]+inter1;

    {calcul du coefficient de Pi(i) dans le premier membre des equations
     issues de la conservation      de la matiere}
    for i:=1 to  rang do begin
    inter2:=0;
     if nombre_solutes_p0>0 then
     for j:=1 to  nombre_solutes_p0 do
     inter2:=inter2+ t_n_a_p_e_solutes[k-1,j-1]*t_n_a_p_e_solutes[i-1,j-1]*
     nombre_moles_equilibre_solutes[j-1];
     mat[k-1,i-1]:=inter2;
     end;
     {coefficient de delta P(i) dans le premier membre des equations
     issues de la conservation      de la matiere}
     inter2:=0;
     if nombre_precipites_p0>0 then
     for i:=1 to nombre_precipites_p0 do
     mat[k-1,rang+1+i-1]:=t_n_a_p_e_precipites[k-1,i-1];
      {coefficient de delta Nsolvant dans le premier membre des equations
     issues de la conservation      de la matiere}
      mat[k-1,rang]:=t_n_a_p_e_solvant[k-1];
     end;

     {equation issue du potentiel chimique de l'eau}
     for i:=1 to rang do
     mat[rang,i-1]:=t_n_a_p_e_solvant[i-1];

      mat[rang,rang]:=0;
      if nombre_precipites_p0>0 then for i:=1 to nombre_precipites_p0 do
        mat[rang,rang+i]:=0;
         mat[rang,rang+2+nombre_precipites_p0-1]:=
         potentiel_chimique_solvant/constante_gaz_parfaits/temperature;

      {equations issues des potnetiels chimiques des precipites}
      if nombre_precipites_p0>0 then
      for k:=1 to nombre_precipites_p0 do begin
      for i:=1 to rang do
     mat[rang+1+k-1,i-1]:=t_n_a_p_e_precipites[i-1,k-1];
      mat[rang+1+k-1,rang+1-1]:=0;
        if nombre_precipites_p0>0 then for i:=1 to nombre_precipites_p0 do
        mat[rang+1+k-1,rang+1+i-1]:=0;
         mat[rang+1+k-1,rang+2+nombre_precipites_p0-1]:=
         potentiels_chimiques_precipites[k-1]/constante_gaz_parfaits/temperature;
       end;


     ResoudLineaire(mat,rang+1+nombre_precipites_p0,delt);


      if nombre_solutes_p0>0 then
     for j:=1 to nombre_solutes_p0 do begin
     inter1:=0;
     for i:=1 to  rang do inter1:=inter1+ t_n_a_p_e_solutes[i-1,j-1]*delt[i-1];
     delta_ln_solutes[j-1]:=inter1-potentiels_chimiques_solutes[j-1]/constante_gaz_parfaits/temperature;
     end;

     delta_solvant:=delt[rang+1-1];

     if nombre_precipites_p0>0 then
     for j:=1 to nombre_precipites_p0 do
     delta_precipites[j-1]:=delt[rang+1+j-1];


           fac1:=0;
        if nombre_solutes_p0>0 then
     for j:=1 to nombre_solutes_p0 do
     if abs(delta_ln_solutes[j-1])>fac1 then fac1:=abs(delta_ln_solutes[j-1]);
     if fac1<>0 then fac1:=2/fac1
        else fac1:=1;

        nombre_total_moles_solutes:=0;
        if nombre_solutes_p0>0 then
        for j:=1 to nombre_solutes_p0 do
        nombre_total_moles_solutes:=nombre_total_moles_solutes+nombre_moles_equilibre_solutes[j-1]
          else nombre_total_moles_solutes:=0.1;


     fac2:=1;
     if nombre_solutes_p0>0 then
     for j:=1 to  nombre_solutes_p0 do
     if  ((nombre_moles_equilibre_solutes[j-1]<1e-8*nombre_total_moles_solutes) and
     (delta_ln_solutes[j-1]>0) and
     (abs((-ln(nombre_moles_equilibre_solutes[j-1]/nombre_total_moles_solutes)-9.2103404)/
     (delta_ln_solutes[j-1]))<fac2)) then
     fac2:=abs((-ln(nombre_moles_equilibre_solutes[j-1]/nombre_total_moles_solutes)-9.2103404)/
     (delta_ln_solutes[j-1]));

     fac:=1;
     if fac1<fac then fac:=fac1;
     if fac2<fac then fac:=fac2;



     if nombre_solutes_p0>0 then
     for j:=1 to nombre_solutes_p0 do
      nombre_moles_equilibre_solutes[j-1]:=
      nombre_moles_equilibre_solutes[j-1]*exp(fac*delta_ln_solutes[j-1]);


      nombre_moles_equilibre_solvant:=nombre_moles_equilibre_solvant+
      fac*delta_solvant;

     if nombre_precipites_p0>0 then
     for j:=1 to nombre_precipites_p0 do
      nombre_moles_equilibre_precipites[j-1]:=
      nombre_moles_equilibre_precipites[j-1]+
      fac*delta_precipites[j-1];




       for i:=1 to  rang do delt_old[i-1]:=delt[i-1];



    setlength(residuconservation,rang);
    setlength(residuconservationrelatif,rang);
   {calcul du residu relatif max des equations de conservation}
   for i:=1 to rang do begin
   setlength(tata,1+nombre_solutes_p0+nombre_precipites_p0+1);
   tata[0]:=aa[i-1,0]*nombre_moles_equilibre_solvant;
   if nombre_solutes_p0>0 then
   for j:=1 to nombre_solutes_p0 do
   tata[j]:=aa[i-1,j]*nombre_moles_equilibre_solutes[j-1];
   if nombre_precipites_p0>0 then
   for j:=1 to nombre_precipites_p0 do
   tata[j+nombre_solutes_p0]:=aa[i-1,j+nombre_solutes_p0]*
   nombre_moles_equilibre_precipites[j-1];
   tata[1+nombre_solutes_p0+nombre_precipites_p0]:=bb[i-1];
   plusgrandelement:=maxabstableau(tata,1+nombre_solutes_p0+nombre_precipites_p0+1);
  residuconservation[i-1]:=0;
  for j:=1 to 1+nombre_solutes_p0+nombre_precipites_p0 do
  residuconservation[i-1]:=residuconservation[i-1]+tata[j-1];
  residuconservation[i-1]:=residuconservation[i-1]
  -tata[1+nombre_solutes_p0+nombre_precipites_p0];
  {on cherche si il n'y a pas un unique terme non nul}
  un_seul_non_nul:=false;
  j:=0;
  repeat
  inc(j);
  until ((tata[j-1]<>0) or (j=1+nombre_solutes_p0+nombre_precipites_p0+1));
    un_seul_non_nul:=true;
    if  j<1+nombre_solutes_p0+nombre_precipites_p0+1 then
    for kkk:=j+1 to 1+nombre_solutes_p0+nombre_precipites_p0+1 do
            if  (tata[kkk-1]<>0) then  un_seul_non_nul:=false;

  {on cherche s'ils ne sont pas tous nuls}
  tous_nuls:=true;
   for j:=1 to 1+nombre_solutes_p0+nombre_precipites_p0+1 do
     tous_nuls:=tous_nuls and (tata[j-1]=0);

  if (not(tous_nuls) and not ( un_seul_non_nul)) then
  if ((plusgrandelement>0) and
  (abs(residuconservation[i-1])> pluspetiteconcentrationsignificative)) then
    residuconservationrelatif[i-1]:=abs(abs(residuconservation[i-1])/plusgrandelement) else
  residuconservationrelatif[i-1]:=0;

    if un_seul_non_nul then
  if ((abs(residuconservation[i-1])< pluspetiteconcentrationsignificative)) then
    residuconservationrelatif[i-1]:=0 else
  residuconservationrelatif[i-1]:=maxresiduconservationrelatif*10;

  if tous_nuls then  residuconservationrelatif[i-1]:=0;
 finalize(tata);
           end;
  plusgrandresiduconservationrelatif:=maxabstableau(residuconservationrelatif,rang);
  {fin du calcul des residus des equations de conservation}


   {calcul du residu des equations de ln K}
            setlength(residuactionmasse,reac);
    setlength(residuactionmasserelatif,reac);
   for i:=1 to reac do begin
   setlength(tata,nombre_solutes_p0+1);
   for j:=1 to nombre_solutes_p0 do if
   nombre_moles_equilibre_solutes[j-1]>0 then
   tata[j-1]:=coeff_stoechio[i-1,j]*ln(nombre_moles_equilibre_solutes[j-1]/volume) else
   tata[j-1]:=0;
   tata[nombre_solutes_p0]:=-deltarg0[i-1]/constante_gaz_parfaits/temperature;
    plusgrandelement:=maxabstableau(tata,1+nombre_solutes_p0);

residuactionmasse[i-1]:=0;
  for j:=1 to nombre_solutes_p0 do
  residuactionmasse[i-1]:=residuactionmasse[i-1]+tata[j-1];
  residuactionmasse[i-1]:=residuactionmasse[i-1]
  -tata[nombre_solutes_p0];
  if ((plusgrandelement>0)  and
  (abs(residuactionmasse[i-1])> pluspetitlnconcentrationsignificatif)) then
  residuactionmasserelatif[i-1]:=abs(abs(residuactionmasse[i-1])/
  plusgrandelement) else
  residuactionmasserelatif[i-1]:=0;
   finalize(tata);
    end;
  plusgrandresiduactionmasserelatif:=maxabstableau(residuactionmasserelatif,reac);
  {fin du calcul des residus des lois d'action de masse}

  finalize(residuactionmasserelatif);
   finalize(residuactionmasse);
   finalize(residuconservationrelatif);
   finalize(residuconservation);

   UNTIL   (    ((plusgrandresiduactionmasserelatif<=maxresiduactionmasserelatif)
   and (plusgrandresiduconservationrelatif<=maxresiduconservationrelatif))
    or (iter>max_iter)  );

    result:=(iter<=max_iter);

      force_ionique:=force_ionique_partie_constante;
    for i:=1 to nombre_solutes_p0 do
   force_ionique:=force_ionique+0.5*sqr(charges_solutes_p0[i-1])*
   nombre_moles_equilibre_solutes[i-1]/volume;

   if not(debye and (force_ionique>0)) then begin

   enthalpie_libre:=nombre_moles_equilibre_solvant*potentiel_chimique_solvant;
      if nombre_precipites_p0>0 then
     for i:=1 to nombre_precipites_p0 do
     if nombre_moles_equilibre_precipites[i-1]>0 then
      enthalpie_libre:=enthalpie_libre+
      nombre_moles_equilibre_precipites[i-1]*potentiels_chimiques_precipites[i-1];



      if nombre_solutes_p0>0 then
   for j:=1 to nombre_solutes_p0 do
   if nombre_moles_equilibre_solutes[j-1]>0 then begin
    potentiels_chimiques_solutes[j-1]:=
    potentiels_chimiques_standards_solutes_p0[j-1]+
    constante_gaz_parfaits*temperature*
    ln(nombre_moles_equilibre_solutes[j-1]/volume);
    enthalpie_libre:=enthalpie_libre+
    nombre_moles_equilibre_solutes[j-1]*potentiels_chimiques_solutes[j-1];
     end;


     setlength(nombre_moles_equilibre_solutes_p0,nombre_solutes_p0);
   setlength(nombre_moles_equilibre_precipites_p0,nombre_precipites_p0);
   for i:=1 to nombre_solutes_p0 do
   nombre_moles_equilibre_solutes_p0[i-1]:=
   nombre_moles_equilibre_solutes[i-1];
   for i:=1 to nombre_precipites_p0 do
   nombre_moles_equilibre_precipites_p0[i-1]:=
   nombre_moles_equilibre_precipites[i-1];
   setlength(nombre_moles_equilibre_solutes,nombre_solutes);
   setlength(activites_solutes,nombre_solutes);
   setlength(nombre_moles_equilibre_precipites,nombre_precipites);
   setlength(potentiels_chimiques_solutes,nombre_solutes);
   setlength(potentiels_chimiques_precipites,nombre_precipites);
   for i:=1 to  nombre_solutes do
   nombre_moles_equilibre_solutes[i-1]:=tableau_nombre_initial_moles_solutes[i-1];
   for i:=1 to  nombre_solutes_p0 do
   nombre_moles_equilibre_solutes[ correspondance_solutes[i-1]-1]:=
     nombre_moles_equilibre_solutes_p0[i-1];
      for i:=1 to  nombre_precipites do
   nombre_moles_equilibre_precipites[i-1]:=tableau_nombre_initial_moles_precipites[i-1];
   for i:=1 to  nombre_precipites_p0 do
   nombre_moles_equilibre_precipites[ correspondance_precipites[i-1]-1]:=
     nombre_moles_equilibre_precipites_p0[i-1];

    enthalpie_libre:=nombre_moles_equilibre_solvant*potentiel_chimique_solvant;
          if nombre_precipites>0 then
     for i:=1 to nombre_precipites do
     if nombre_moles_equilibre_precipites[i-1]>0 then
      enthalpie_libre:=enthalpie_libre+
      nombre_moles_equilibre_precipites[i-1]*potentiels_chimiques_precipites[i-1];
           if nombre_solutes>0 then
   for j:=1 to nombre_solutes do
   if nombre_moles_equilibre_solutes[j-1]>0 then begin
    potentiels_chimiques_solutes[j-1]:= potentiels_chimiques_standards_solutes[j-1]+
    constante_gaz_parfaits*temperature*ln(nombre_moles_equilibre_solutes[j-1]/volume);
     activites_solutes[j-1]:=nombre_moles_equilibre_solutes[j-1]/volume;
    enthalpie_libre:=enthalpie_libre+
    nombre_moles_equilibre_solutes[j-1]*potentiels_chimiques_solutes[j-1];
     end else  activites_solutes[j-1]:=0;


   end else begin
    {si on tient  compte de Debye-Huckel}


     iter:=0;

   REPEAT
   inc(iter);

    force_ionique:=force_ionique_partie_constante;
   if nombre_solutes_p0>0 then
    for i:=1 to nombre_solutes_p0 do
   force_ionique:=force_ionique+0.5*sqr(charges_solutes_p0[i-1])*
   nombre_moles_equilibre_solutes[i-1]/volume;

   if nombre_solutes_p0>0 then
   for j:=1 to nombre_solutes_p0 do
    potentiels_chimiques_solutes[j-1]:= potentiels_chimiques_standards_solutes_p0[j-1]+
    constante_gaz_parfaits*temperature*(
    ln(nombre_moles_equilibre_solutes[j-1]/volume)-
    ln(10)*a_debye*sqr(charges_solutes_p0[j-1])*sqrt(force_ionique)/
    (1+b_debye*rayons_solutes_p0[j-1]*sqrt(force_ionique)));

    for k:=1 to rang do begin

    {calcul du seond membre des equations issues de la conservation
    de la matiere}
    inter1:=0;
    if nombre_solutes_p0>0 then
    for j:=1 to nombre_solutes_p0 do
    inter1:=inter1+t_n_a_p_e_solutes[k-1,j-1]*nombre_moles_equilibre_solutes[j-1]*
    (potentiels_chimiques_solutes[j-1]/constante_gaz_parfaits/temperature-1);
    inter1:=inter1-t_n_a_p_e_solvant[k-1]*nombre_moles_equilibre_solvant;
    if nombre_precipites_p0>0 then
    for j:=1 to nombre_precipites_p0 do
    inter1:=inter1-t_n_a_p_e_precipites[k-1,j-1]*nombre_moles_equilibre_precipites[j-1];

        mat[k-1,rang+2+nombre_precipites_p0-1]:=t_n_a[k-1]+inter1;

    {calcul du coefficient de Pi(i) dans le premier membre des equations
     issues de la conservation      de la matiere}
    for i:=1 to  rang do begin
    inter2:=0;
     if nombre_solutes_p0>0 then
     for j:=1 to  nombre_solutes_p0 do
     inter2:=inter2+ t_n_a_p_e_solutes[k-1,j-1]*t_n_a_p_e_solutes[i-1,j-1]*
     nombre_moles_equilibre_solutes[j-1];
     mat[k-1,i-1]:=inter2;
     end;
     {coefficient de delta P(i) dans le premier membre des equations
     issues de la conservation      de la matiere}
     inter2:=0;
     if nombre_precipites_p0>0 then
     for i:=1 to nombre_precipites_p0 do
     mat[k-1,rang+1+i-1]:=t_n_a_p_e_precipites[k-1,i-1];
      {coefficient de delta Nsolvant dans le premier membre des equations
     issues de la conservation      de la matiere}
      mat[k-1,rang]:=t_n_a_p_e_solvant[k-1];
     end;

     {equation issue du potentiel chimique de l'eau}
     for i:=1 to rang do
     mat[rang,i-1]:=t_n_a_p_e_solvant[i-1];

      mat[rang,rang]:=0;
      if nombre_precipites_p0>0 then for i:=1 to nombre_precipites_p0 do
        mat[rang,rang+i]:=0;
         mat[rang,rang+2+nombre_precipites_p0-1]:=
         potentiel_chimique_solvant/constante_gaz_parfaits/temperature;

      {equations issues des potnetiels chimiques des precipites}
      if nombre_precipites_p0>0 then
      for k:=1 to nombre_precipites_p0 do begin
      for i:=1 to rang do
     mat[rang+1+k-1,i-1]:=t_n_a_p_e_precipites[i-1,k-1];
      mat[rang+1+k-1,rang+1-1]:=0;
        if nombre_precipites_p0>0 then for i:=1 to nombre_precipites_p0 do
        mat[rang+1+k-1,rang+1+i-1]:=0;
         mat[rang+1+k-1,rang+2+nombre_precipites_p0-1]:=
         potentiels_chimiques_precipites[k-1]/constante_gaz_parfaits/temperature;
       end;


     ResoudLineaire(mat,rang+1+nombre_precipites_p0,delt);


      if nombre_solutes_p0>0 then
     for j:=1 to nombre_solutes_p0 do begin
     inter1:=0;
     for i:=1 to  rang do inter1:=inter1+ t_n_a_p_e_solutes[i-1,j-1]*delt[i-1];
     delta_ln_solutes[j-1]:=inter1-potentiels_chimiques_solutes[j-1]/constante_gaz_parfaits/temperature;
     end;

     delta_solvant:=delt[rang+1-1];

     if nombre_precipites_p0>0 then
     for j:=1 to nombre_precipites_p0 do
     delta_precipites[j-1]:=delt[rang+1+j-1];


           fac1:=0;
        if nombre_solutes_p0>0 then
     for j:=1 to nombre_solutes_p0 do
     if abs(delta_ln_solutes[j-1])>fac1 then fac1:=abs(delta_ln_solutes[j-1]);
     if fac1<>0 then fac1:=2/fac1
        else fac1:=1;

        nombre_total_moles_solutes:=0;
        if nombre_solutes_p0>0 then
        for j:=1 to nombre_solutes_p0 do
        nombre_total_moles_solutes:=nombre_total_moles_solutes+nombre_moles_equilibre_solutes[j-1]
          else nombre_total_moles_solutes:=0.1;


     fac2:=1;
     if nombre_solutes_p0>0 then
     for j:=1 to  nombre_solutes_p0 do
     if  ((nombre_moles_equilibre_solutes[j-1]<1e-8*nombre_total_moles_solutes) and
     (delta_ln_solutes[j-1]>0) and
     (abs((-ln(nombre_moles_equilibre_solutes[j-1]/nombre_total_moles_solutes)-9.2103404)/
     (delta_ln_solutes[j-1]))<fac2)) then
     fac2:=abs((-ln(nombre_moles_equilibre_solutes[j-1]/nombre_total_moles_solutes)-9.2103404)/
     (delta_ln_solutes[j-1]));

     fac:=1;
     if fac1<fac then fac:=fac1;
     if fac2<fac then fac:=fac2;



     if nombre_solutes_p0>0 then
     for j:=1 to nombre_solutes_p0 do
      nombre_moles_equilibre_solutes[j-1]:=
      nombre_moles_equilibre_solutes[j-1]*exp(fac*delta_ln_solutes[j-1]);


      nombre_moles_equilibre_solvant:=nombre_moles_equilibre_solvant+
      fac*delta_solvant;

     if nombre_precipites_p0>0 then
     for j:=1 to nombre_precipites_p0 do
      nombre_moles_equilibre_precipites[j-1]:=
      nombre_moles_equilibre_precipites[j-1]+
      fac*delta_precipites[j-1];




       for i:=1 to  rang do delt_old[i-1]:=delt[i-1];



    setlength(residuconservation,rang);
    setlength(residuconservationrelatif,rang);
   {calcul du residu relatif max des equations de conservation}
   for i:=1 to rang do begin
   setlength(tata,1+nombre_solutes_p0+nombre_precipites_p0+1);
   tata[0]:=a[i-1,0]*nombre_moles_equilibre_solvant;
   if nombre_solutes_p0>0 then
   for j:=1 to nombre_solutes_p0 do
   tata[j]:=a[i-1,j]*nombre_moles_equilibre_solutes[j-1];
   if nombre_precipites_p0>0 then
   for j:=1 to nombre_precipites_p0 do
   tata[j+nombre_solutes_p0]:=a[i-1,j+nombre_solutes_p0]*
   nombre_moles_equilibre_precipites[j-1];
   tata[1+nombre_solutes_p0+nombre_precipites_p0]:=b[i-1];
   plusgrandelement:=maxabstableau(tata,1+nombre_solutes_p0+nombre_precipites_p0+1);
  residuconservation[i-1]:=0;
  for j:=1 to 1+nombre_solutes_p0+nombre_precipites_p0 do
  residuconservation[i-1]:=residuconservation[i-1]+tata[j-1];
  residuconservation[i-1]:=residuconservation[i-1]
  -tata[1+nombre_solutes_p0+nombre_precipites_p0];
  {on cherche si il n'y a pas un unique terme non nul}
  un_seul_non_nul:=false;
  j:=0;
  repeat
  inc(j);
  until ((tata[j-1]<>0) or (j=1+nombre_solutes_p0+nombre_precipites_p0+1));
    un_seul_non_nul:=true;
    if  j<1+nombre_solutes_p0+nombre_precipites_p0+1 then
    for kkk:=j+1 to 1+nombre_solutes_p0+nombre_precipites_p0+1 do
            if  (tata[kkk-1]<>0) then  un_seul_non_nul:=false;

  {on cherche s'ils ne sont pas tous nuls}
  tous_nuls:=true;
   for j:=1 to 1+nombre_solutes_p0+nombre_precipites_p0+1 do
     tous_nuls:=tous_nuls and (tata[j-1]=0);

  if (not(tous_nuls) and not ( un_seul_non_nul)) then
  if ((plusgrandelement>0) and
  (abs(residuconservation[i-1])> pluspetiteconcentrationsignificative)) then
    residuconservationrelatif[i-1]:=abs(abs(residuconservation[i-1])/plusgrandelement) else
  residuconservationrelatif[i-1]:=0;

    if un_seul_non_nul then
  if ((abs(residuconservation[i-1])< pluspetiteconcentrationsignificative)) then
    residuconservationrelatif[i-1]:=0 else
  residuconservationrelatif[i-1]:=maxresiduconservationrelatif*10;

  if tous_nuls then  residuconservationrelatif[i-1]:=0;
 finalize(tata);
           end;
  plusgrandresiduconservationrelatif:=maxabstableau(residuconservationrelatif,rang);
  {fin du calcul des residus des equations de conservation}


   {calcul du residu des equations de ln K}

            setlength(residuactionmasse,reac);
    setlength(residuactionmasserelatif,reac);
   for i:=1 to reac do begin
   setlength(tata,nombre_solutes_p0+1);
   for j:=1 to nombre_solutes_p0 do if
   nombre_moles_equilibre_solutes[j-1]>0 then
   tata[j-1]:=coeff_stoechio[i-1,j]*(
    ln(nombre_moles_equilibre_solutes[j-1]/volume)-
    ln(10)*a_debye*sqr(charges_solutes_p0[j-1])*sqrt(force_ionique)/
    (1+b_debye*rayons_solutes_p0[j-1]*sqrt(force_ionique)))
    else
   tata[j-1]:=0;
   tata[nombre_solutes_p0]:=-deltarg0[i-1]/constante_gaz_parfaits/temperature;
    plusgrandelement:=maxabstableau(tata,1+nombre_solutes_p0);

residuactionmasse[i-1]:=0;
  for j:=1 to nombre_solutes_p0 do
  residuactionmasse[i-1]:=residuactionmasse[i-1]+tata[j-1];
  residuactionmasse[i-1]:=residuactionmasse[i-1]
  -tata[nombre_solutes_p0];
  if ((plusgrandelement>0)  and
  (abs(residuactionmasse[i-1])> pluspetitlnconcentrationsignificatif)) then
  residuactionmasserelatif[i-1]:=abs(abs(residuactionmasse[i-1])/
  plusgrandelement) else
  residuactionmasserelatif[i-1]:=0;
   finalize(tata);
    end;
  plusgrandresiduactionmasserelatif:=maxabstableau(residuactionmasserelatif,reac);
  {fin du calcul des residus des lois d'action de masse}

  finalize(residuactionmasserelatif);
   finalize(residuactionmasse);
   finalize(residuconservationrelatif);
   finalize(residuconservation);

   UNTIL   (    ((plusgrandresiduactionmasserelatif<=maxresiduactionmasserelatif)
   and (plusgrandresiduconservationrelatif<=maxresiduconservationrelatif))
    or (iter>max_iter)  );

    result:=(iter<=max_iter);



     enthalpie_libre:=nombre_moles_equilibre_solvant*potentiel_chimique_solvant;
      if nombre_precipites_p0>0 then
     for i:=1 to nombre_precipites_p0 do
     if nombre_moles_equilibre_precipites[i-1]>0 then
      enthalpie_libre:=enthalpie_libre+
      nombre_moles_equilibre_precipites[i-1]*potentiels_chimiques_precipites[i-1];



      if nombre_solutes_p0>0 then
   for j:=1 to nombre_solutes_p0 do
   if nombre_moles_equilibre_solutes[j-1]>0 then begin
    potentiels_chimiques_solutes[j-1]:=
    potentiels_chimiques_standards_solutes_p0[j-1]+
    constante_gaz_parfaits*temperature*(
    ln(nombre_moles_equilibre_solutes[j-1]/volume)-
    ln(10)*a_debye*sqr(charges_solutes_p0[j-1])*sqrt(force_ionique)/
    (1+b_debye*rayons_solutes_p0[j-1]*sqrt(force_ionique)));
    enthalpie_libre:=enthalpie_libre+
    nombre_moles_equilibre_solutes[j-1]*potentiels_chimiques_solutes[j-1];
     end;


     setlength(nombre_moles_equilibre_solutes_p0,nombre_solutes_p0);
   setlength(nombre_moles_equilibre_precipites_p0,nombre_precipites_p0);
   for i:=1 to nombre_solutes_p0 do
   nombre_moles_equilibre_solutes_p0[i-1]:=
   nombre_moles_equilibre_solutes[i-1];
   for i:=1 to nombre_precipites_p0 do
   nombre_moles_equilibre_precipites_p0[i-1]:=
   nombre_moles_equilibre_precipites[i-1];
   setlength(nombre_moles_equilibre_solutes,nombre_solutes);
   setlength(activites_solutes,nombre_solutes);
   setlength(nombre_moles_equilibre_precipites,nombre_precipites);
   setlength(potentiels_chimiques_solutes,nombre_solutes);
   setlength(potentiels_chimiques_precipites,nombre_precipites);
   for i:=1 to  nombre_solutes do
   nombre_moles_equilibre_solutes[i-1]:=tableau_nombre_initial_moles_solutes[i-1];
   for i:=1 to  nombre_solutes_p0 do
   nombre_moles_equilibre_solutes[ correspondance_solutes[i-1]-1]:=
     nombre_moles_equilibre_solutes_p0[i-1];
      for i:=1 to  nombre_precipites do
   nombre_moles_equilibre_precipites[i-1]:=tableau_nombre_initial_moles_precipites[i-1];
   for i:=1 to  nombre_precipites_p0 do
   nombre_moles_equilibre_precipites[ correspondance_precipites[i-1]-1]:=
     nombre_moles_equilibre_precipites_p0[i-1];

      force_ionique:=0;
    for i:=1 to nombre_solutes do
   force_ionique:=force_ionique+0.5*sqr(charges_solutes_0[i-1])*
   nombre_moles_equilibre_solutes[i-1]/volume;
    enthalpie_libre:=nombre_moles_equilibre_solvant*potentiel_chimique_solvant;
          if nombre_precipites>0 then
     for i:=1 to nombre_precipites do
     if nombre_moles_equilibre_precipites[i-1]>0 then
      enthalpie_libre:=enthalpie_libre+
      nombre_moles_equilibre_precipites[i-1]*potentiels_chimiques_precipites[i-1];
           if nombre_solutes>0 then
   for j:=1 to nombre_solutes do
   if nombre_moles_equilibre_solutes[j-1]>0 then begin
    potentiels_chimiques_solutes[j-1]:= potentiels_chimiques_standards_solutes[j-1]+
    constante_gaz_parfaits*temperature*(
    ln(nombre_moles_equilibre_solutes[j-1]/volume)-
    ln(10)*a_debye*sqr(charges_solutes_0[j-1])*sqrt(force_ionique)/
    (1+b_debye*rayons_solutes_0[j-1]*sqrt(force_ionique)));
    activites_solutes[j-1]:=exp(
    ln(nombre_moles_equilibre_solutes[j-1]/volume)-
    ln(10)*a_debye*sqr(charges_solutes_0[j-1])*sqrt(force_ionique)/
    (1+b_debye*rayons_solutes[j-1]*sqrt(force_ionique)));
    enthalpie_libre:=enthalpie_libre+
    nombre_moles_equilibre_solutes[j-1]*potentiels_chimiques_solutes[j-1];
     end else  activites_solutes[j-1]:=0;

     end;
    {du cas ou on utilise Debye et Huckel}

     finalize(potentiels_chimiques_precipites);
 finalize(potentiels_chimiques_solutes);
 finalize(mat);
 finalize(delta_ln_solutes);
 finalize(delta_precipites);
 finalize(delt);
 finalize(delt_old);
  finalize(t_n_a);
  finalize(a);
  finalize(aa);
  finalize(coeff_stoechio);
  finalize(b);
  finalize(bb);
  finalize(potentiel_standard);
  finalize(deltarg0);
  finalize(noms_1);
  finalize(f_b_1);
  finalize(reactions);
  finalize(equations_conservation);
  finalize(equations_avancements);
  finalize( t_n_a_p_e_solvant);
 finalize(t_n_a_p_e_solutes);
 finalize(t_n_a_p_e_precipites);
   finalize(moles_initiales_atomes_0);
finalize(correspondance_atomes);
 finalize(correspondance_solutes);
 finalize(correspondance_precipites);
   finalize(atomes_de_concentration_nulle);
   finalize(solutes_de_concentration_bloquee);
   finalize(precipites_de_concentration_bloquee);
   finalize(t_n_a_p_e_solvant_p0);
 finalize(t_n_a_p_e_solutes_p0);
 finalize(t_n_a_p_e_precipites_p0);
 finalize(tableau_nombre_initial_moles_solutes_p0);
 finalize(tableau_nombre_initial_moles_precipites_p0);
  finalize(noms_solutes_p0);
   finalize(potentiels_chimiques_standards_solutes_p0);
  finalize(potentiels_chimiques_standards_precipites_p0);
  finalize(noms_precipites_p0);
  finalize(moles_initiales_atomes_0_p0);
  finalize(reactions_bloquees);
  finalize(charges_solutes_p0);
  finalize(rayons_solutes_p0);
  finalize(nombre_moles_equilibre_solutes_p0);
  finalize(nombre_moles_equilibre_precipites_p0);
     end;




       function calcule_equilibre_solution_aqueuse_avec_precipites(nombre_solutes,nombre_precipites,nombre_type_atomes:integer;
nombre_initial_moles_solvant:float;
tableau_nombre_initial_moles_solutes,tableau_nombre_initial_moles_precipites:_tableau_nombres_atomes;
 t_n_a_p_e_solvant:tableaureel;
 t_n_a_p_e_solutes,t_n_a_p_e_precipites:matricereelle;
 nom_solvant:string;
 noms_solutes,noms_precipites:tableaustring;
 var nombre_moles_equilibre_solvant:float;
var nombre_moles_equilibre_solutes,nombre_moles_equilibre_precipites,
activites_solutes: _nombres_moles;
potentiel_chimique_standard_solvant:float;
potentiels_chimiques_standards_solutes,potentiels_chimiques_standards_precipites,
rayons_solutes:_nombres_moles;
volume,temperature,maxresiduconservationrelatif,
maxresiduactionmasserelatif:float;max_iter:integer; var iter:integer;
var enthalpie_libre:float;
debye:boolean):boolean;

 var i,j,k,iii,jjj,kkk,nombre_precipites_actuel,iter_p,lili,jiji:integer;
present:_tableau_presents;
quotients_reactions:array of float;
retenue1,retenue2,tentative,tous_positifs,une_solution_trouvee,quotient_ok:boolean;
 nombre_moles_equilibre_solvant_p,plusgrandelement:float;
  nombre_moles_equilibre_solutes_p,activites_solutes_p,
  nombre_moles_equilibre_precipites_p: _nombres_moles;
  enthalpie_libre_p,enthalpie_libre_provisoire,plusgrandresiduconservationrelatif:float;
  t_noms_precipites_p:tableaustring;
   t_n_a_p_e_precipites_p:matricereelle;
   potentiels_chimiques_standards_precipites_p,tableau_nombre_initial_moles_precipites_p:_nombres_moles;
residuconservationrelatif,residuconservation,tata:tableaureel;
moles_initiales_atomes_0,nombre_moles_equilibre_precipites_p_p:tableaureel;

{modif version 2.5}
var solide_exclu:array of boolean;
un_des_constituants_est_O2,il_existe_un_solide_exclu,ne_fait_pas_partie_dun_couple_redox:boolean;
indice_couple,indice_couple_correspondant:integer;
             label 9090,8080,7070;
{modif version 2.5}
begin

setlength(moles_initiales_atomes_0,nombre_type_atomes);
for i:=1 to  nombre_type_atomes do begin
moles_initiales_atomes_0[i-1]:= t_n_a_p_e_solvant[i-1]*nombre_initial_moles_solvant;
if nombre_solutes>0 then
 for j:=1 to nombre_solutes do
  moles_initiales_atomes_0[i-1]:=moles_initiales_atomes_0[i-1]+
       t_n_a_p_e_solutes[i-1,j-1]*tableau_nombre_initial_moles_solutes[j-1];
 if nombre_precipites>0 then
 for j:=1 to nombre_precipites do
  moles_initiales_atomes_0[i-1]:=moles_initiales_atomes_0[i-1]+
       t_n_a_p_e_precipites[i-1,j-1]*tableau_nombre_initial_moles_precipites[j-1];
         end;


         {modif version 2.5}

            if empecher_redox_eau then   begin
  {on regarde si, en l'absence de reaction redox, il y a un solide
       qui ne pourrait apparaitre que par reaction redox: celui-la ne voit pas
       son nombre de moles changer et on ne peut faire le test sans precipite}

  {on cherche les solides a exclure}
  il_existe_un_solide_exclu:=false;
               setlength(solide_exclu,nombre_precipites);
      if nombre_precipites>0 then
      for j:=1 to nombre_precipites do begin
  solide_exclu[j-1]:=(empecher_redox_eau and (tableau_nombre_initial_moles_precipites[j-1]>0));
     jjj:=Unit2.indice_element_mineral(noms_precipites[j-1]);
     un_des_constituants_est_O2:=false;
 for kkk:=1 to unit2.tableau_elements_mineraux[jjj-1].nombre_composants do
 if   unit2.tableau_elements_mineraux[jjj-1].composition[kkk-1].element='O2(aq)' then
 un_des_constituants_est_O2:=true;
 solide_exclu[j-1]:=solide_exclu[j-1] and un_des_constituants_est_O2;
 if  solide_exclu[j-1] then  il_existe_un_solide_exclu:=true;
 end;
   {fin recherche solides  a exclure}

 end; {du cas ou reactions redox interdites}
 {si les reactions redox sont autorisees et qu'un solide ne peut se former que par reaction redox,
 on regarde s'il fait partie d'un des couple redox present ds le milieu et si la reactions avec un autre couple
 redox ne comprenant pas de solide est equilibrable }
 {modif version 2.5}

            if not(empecher_redox_eau) then   begin
    {on cherche les solides a exclure}
  il_existe_un_solide_exclu:=false;
               setlength(solide_exclu,nombre_precipites);
      if nombre_precipites>0 then
      for j:=1 to nombre_precipites do begin
  solide_exclu[j-1]:=tableau_nombre_initial_moles_precipites[j-1]>0;
     jjj:=Unit2.indice_element_mineral(noms_precipites[j-1]);
     un_des_constituants_est_O2:=false;
 for kkk:=1 to unit2.tableau_elements_mineraux[jjj-1].nombre_composants do
 if   unit2.tableau_elements_mineraux[jjj-1].composition[kkk-1].element='O2(aq)' then
 un_des_constituants_est_O2:=true;
 solide_exclu[j-1]:=solide_exclu[j-1] and un_des_constituants_est_O2;
 if not(solide_exclu[j-1])  then continue;
 {on verifie s'il fait partie d'un des couples redox}
 ne_fait_pas_partie_dun_couple_redox:=true;
 for kkk:=1 to nombre_couples_redox do
 ne_fait_pas_partie_dun_couple_redox:=ne_fait_pas_partie_dun_couple_redox
  and not((liste_couples_redox[kkk-1].espece1=noms_precipites[j-1]) or
  (liste_couples_redox[kkk-1].espece2=noms_precipites[j-1]));
  if ne_fait_pas_partie_dun_couple_redox then continue;
  {s'il ne fait partie d'aucun couple, il reste exclu, son nombre de moles ne peut varier;
  sinon, on va voir si on peut le remplacer par des constituants issus d'une reaction redox}

 for kkk:=1 to nombre_couples_redox do
 if ((liste_couples_redox[kkk-1].espece1=noms_precipites[j-1]) or
  (liste_couples_redox[kkk-1].espece2=noms_precipites[j-1])) then
  begin
  indice_couple:=kkk;
  break;
  end;

  indice_couple_correspondant:=0;
 for kkk:=1 to nombre_couples_redox do begin
 if kkk=indice_couple then continue;
if ( (indice_element_mineral(liste_couples_redox[kkk-1].espece1)>0)
or (indice_element_mineral(liste_couples_redox[kkk-1].espece2)>0)) then continue else
begin
nombre_especes_redox:=6;
setlength(noms_especes_redox,nombre_especes_redox);
 setlength(formules_brutes_redox,nombre_especes_redox);
 setlength(tableau_moles_initiales_redox,nombre_especes_redox);
  setlength(potentiels_standards_redox,nombre_especes_redox);
    noms_especes_redox[0]:='H2O';
    noms_especes_redox[1]:='H[+]';
     noms_especes_redox[2]:=liste_couples_redox[kkk-1].espece1;
     noms_especes_redox[3]:=liste_couples_redox[kkk-1].espece2;
        noms_especes_redox[4]:=liste_couples_redox[indice_couple-1].espece1;
     noms_especes_redox[5]:=liste_couples_redox[indice_couple-1].espece2;
      formules_brutes_redox[0]:='H2O';
    formules_brutes_redox[1]:='H[+]';
     formules_brutes_redox[2]:=liste_couples_redox[kkk-1].formule_brute_espece1;
    formules_brutes_redox[3]:=liste_couples_redox[kkk-1].formule_brute_espece2;
     formules_brutes_redox[4]:=liste_couples_redox[indice_couple-1].formule_brute_espece1;
    formules_brutes_redox[5]:=liste_couples_redox[indice_couple-1].formule_brute_espece2;
     tableau_moles_initiales_redox[0]:=1;
     tableau_moles_initiales_redox[1]:=1;
     tableau_moles_initiales_redox[2]:=1;
     tableau_moles_initiales_redox[3]:=1;
     tableau_moles_initiales_redox[4]:=1;
          tableau_moles_initiales_redox[5]:=1;
     potentiels_standards_redox[0]:=0;
     potentiels_standards_redox[1]:=0;
     potentiels_standards_redox[2]:=0;
     potentiels_standards_redox[3]:=0;
     potentiels_standards_redox[4]:=0;
     potentiels_standards_redox[5]:=0;
 DonneMatriceCoefficients(formules_brutes_redox,matrice_redox, nombre_especes_redox,nombre_atomes_redox);
 DetermineReactions(matrice_redox,  tableau_moles_initiales_redox,
nombre_especes_redox,nombre_atomes_redox,
noms_especes_redox,formules_brutes_redox,
rang_redox,reac_redox,
reactions_redox,equations_conservation_redox,equations_avancements_redox,
aaa_redox, b_redox,
coeff_stoechio_redox,
potentiels_standards_redox,
deltarG0_redox,logK_redox,
temperature);
if  reac_redox<>1 then continue;
{ca y est, on a trouve un couple accorde}
if  liste_couples_redox[indice_couple-1].espece1=noms_precipites[j-1] then begin
nombre_initial_moles_solvant:=nombre_initial_moles_solvant- coeff_stoechio_redox[0,0]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,4];
 for iii:=1 to nombre_solutes do  begin
if noms_solutes[iii-1]=liste_couples_redox[indice_couple-1].espece2 then
tableau_nombre_initial_moles_solutes[iii-1]:=tableau_nombre_initial_moles_solutes[iii-1]
-coeff_stoechio_redox[0,5]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,4];
if noms_solutes[iii-1]=liste_couples_redox[kkk-1].espece1 then
tableau_nombre_initial_moles_solutes[iii-1]:=tableau_nombre_initial_moles_solutes[iii-1]
-coeff_stoechio_redox[0,2]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,4];
if noms_solutes[iii-1]=liste_couples_redox[kkk-1].espece2 then
tableau_nombre_initial_moles_solutes[iii-1]:=tableau_nombre_initial_moles_solutes[iii-1]
-coeff_stoechio_redox[0,3]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,4];
if 'H[+]'=noms_solutes[iii-1] then
tableau_nombre_initial_moles_solutes[iii-1]:=tableau_nombre_initial_moles_solutes[iii-1]
-coeff_stoechio_redox[0,1]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,4];
end;    end;
 if  liste_couples_redox[indice_couple-1].espece2=noms_precipites[j-1] then begin
nombre_initial_moles_solvant:=nombre_initial_moles_solvant- coeff_stoechio_redox[0,0]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,5];
 for iii:=1 to nombre_solutes do  begin
if noms_solutes[iii-1]=liste_couples_redox[indice_couple-1].espece1 then
tableau_nombre_initial_moles_solutes[iii-1]:=tableau_nombre_initial_moles_solutes[iii-1]
-coeff_stoechio_redox[0,4]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,5];
if noms_solutes[iii-1]=liste_couples_redox[kkk-1].espece1 then
tableau_nombre_initial_moles_solutes[iii-1]:=tableau_nombre_initial_moles_solutes[iii-1]
-coeff_stoechio_redox[0,2]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,5];
if noms_solutes[iii-1]=liste_couples_redox[kkk-1].espece2 then
tableau_nombre_initial_moles_solutes[iii-1]:=tableau_nombre_initial_moles_solutes[iii-1]
-coeff_stoechio_redox[0,3]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,5];
if 'H[+]'=noms_solutes[iii-1] then
tableau_nombre_initial_moles_solutes[iii-1]:=tableau_nombre_initial_moles_solutes[iii-1]
-coeff_stoechio_redox[0,1]
*tableau_nombre_initial_moles_precipites[j-1]/coeff_stoechio_redox[0,5];
end;   end;
tableau_nombre_initial_moles_precipites[j-1]:=0;
indice_couple_correspondant:=kkk;
solide_exclu[j-1]:=false;
break;
end;
end;
 if  solide_exclu[j-1] then  il_existe_un_solide_exclu:=true;
  end;

 end;
   {fin recherche solides  a exclure}


{si il y a des precipites non exclus presents initialement, on les remplace par leurs elements constitutifs}
          if nombre_precipites>0 then
 for j:=1 to nombre_precipites do
 if ((tableau_nombre_initial_moles_precipites[j-1]>0) and not(solide_exclu[j-1]))
  then begin
 jjj:=Unit2.indice_element_mineral(noms_precipites[j-1]);
 for kkk:=1 to unit2.tableau_elements_mineraux[jjj-1].nombre_composants do begin
 if   unit2.tableau_elements_mineraux[jjj-1].composition[kkk-1].element='H2O' then
nombre_initial_moles_solvant:=nombre_initial_moles_solvant+
unit2.tableau_elements_mineraux[jjj-1].composition[kkk-1].coefficient*
tableau_nombre_initial_moles_precipites[j-1] else
begin
i:=0;
for iii:=1 to nombre_solutes do
if noms_solutes[iii-1]=unit2.tableau_elements_mineraux[jjj-1].composition[kkk-1].element then
i:=iii;

if i=0 then begin
application.messagebox(pchar('Probleme pour '+noms_precipites[j-1]+
': un des éléments constitutifs n''est pas un soluté !'),'Attention !',mb_ok);
exit;
end;

tableau_nombre_initial_moles_solutes[i-1]:=tableau_nombre_initial_moles_solutes[i-1]+
unit2.tableau_elements_mineraux[jjj-1].composition[kkk-1].coefficient*
tableau_nombre_initial_moles_precipites[j-1];
end;
 end;
tableau_nombre_initial_moles_precipites[j-1]:=0;
 end;
   {modif version 2.5}
 if  il_existe_un_solide_exclu then begin
  enthalpie_libre :=1.1e4932	;
 goto 9090;
 end;
 {modif version 2.5}

{1er calcul sans precipites}
une_solution_trouvee:=calcule_equilibre_phase_aqueuse_annexe(nombre_solutes,0,nombre_type_atomes,
nombre_initial_moles_solvant,tableau_nombre_initial_moles_solutes,tableau_nombre_initial_moles_precipites,
moles_initiales_atomes_0,
t_n_a_p_e_solvant, t_n_a_p_e_solutes,t_n_a_p_e_precipites,
nom_solvant,noms_solutes,noms_precipites,
 nombre_moles_equilibre_solvant,
nombre_moles_equilibre_solutes,nombre_moles_equilibre_precipites,activites_solutes,
potentiel_chimique_standard_solvant,
potentiels_chimiques_standards_solutes,potentiels_chimiques_standards_precipites,
rayons_solutes_0,
volume,temperature,maxresiduconservationrelatif,
maxresiduactionmasserelatif,max_iter,iter,enthalpie_libre,debye);
{modif version 2.5}
if not(une_solution_trouvee) then enthalpie_libre :=1.1e4932;
{modif version 2.5}
if une_solution_trouvee then begin
tous_positifs:=true;
 for iii:=1 to  nombre_solutes do tous_positifs:=
 (tous_positifs and (nombre_moles_equilibre_solutes[iii-1]>=0));
une_solution_trouvee:=une_solution_trouvee and  tous_positifs;
if nombre_precipites=0 then begin
finalize(moles_initiales_atomes_0);
result:= une_solution_trouvee;
exit;
end;

quotient_ok:=true;
{on verifie si, dans le cas ou il pourrait y avoir des precipites, les quotients de reaction sont tels
que ces precipites n'existent effectivement pas}
if nombre_precipites>0 then begin
{calcul des quotients de reaction}
setlength(quotients_reactions,unit1.reac_0);
for iii:=1 to unit1.reac_0 do begin
quotients_reactions[iii-1]:=0;
for jjj:=1 to unit1.nombre_especes_0 do
if unit1.liste_genre_espece[jjj-1]=solute then
if activites_solutes[unit1.indices_solutes[jjj-1]-1]>0 then
quotients_reactions[iii-1]:=quotients_reactions[iii-1]+unit1.coeff_stoechio_0[iii-1,jjj-1]*
ln(activites_solutes[unit1.indices_solutes[jjj-1]-1])/ln(10);
end; {du calcul des quotients de reactions}

for iii:=1 to nombre_precipites do
for jjj:=1 to  unit1.reac_0 do
if   unit1.coeff_stoechio_0[jjj-1,unit1.indices_precipites_inverses[iii-1]-1]<>0 then
begin
quotient_ok:=quotient_ok and
(
((unit1.coeff_stoechio_0[jjj-1,unit1.indices_precipites_inverses[iii-1]-1]>0) and
(quotients_reactions[jjj-1]>unit1.logk_0[jjj-1]))
or
 ((unit1.coeff_stoechio_0[jjj-1,unit1.indices_precipites_inverses[iii-1]-1]<0) and
(quotients_reactions[jjj-1]<unit1.logk_0[jjj-1]))
);

end; {de la boucle des precipites}
if quotient_ok then begin
setlength(nombre_moles_equilibre_precipites,nombre_precipites);
for iii:=1 to nombre_precipites do
nombre_moles_equilibre_precipites[iii-1]:=0;
end;
une_solution_trouvee:=une_solution_trouvee and  quotient_ok;
end; {du cas ou nombre_precipites>0}
end; {du cas ou une_solution_trouvee}

if not(quotient_ok) then  une_solution_trouvee:=false;

 {modif version 2.5}
 9090:
  {modif version 2.5}
setlength(nombre_moles_equilibre_precipites_p_p,nombre_precipites);

  setlength(residuconservation,nombre_type_atomes);
    setlength(residuconservationrelatif,nombre_type_atomes);


setlength(present,nombre_precipites);
setlength(nombre_moles_equilibre_solutes_p,nombre_solutes);
setlength(nombre_moles_equilibre_solutes,nombre_solutes);
setlength(activites_solutes_p,nombre_solutes);
setlength(activites_solutes,nombre_solutes);
setlength(nombre_moles_equilibre_precipites_p,nombre_precipites);

setlength(tableau_nombre_initial_moles_precipites_p,nombre_precipites);
setlength(t_n_a_p_e_precipites_p,nombre_type_atomes,nombre_precipites);
setlength(potentiels_chimiques_standards_precipites_p,nombre_precipites);
setlength(t_noms_precipites_p,nombre_precipites);
      setlength(nombre_moles_equilibre_precipites,nombre_precipites);
 for i:=1 to nombre_precipites do
  {modif version 2.5}
  if not(solide_exclu[i-1]) then nombre_moles_equilibre_precipites[i-1]:=0;
    {modif version 2.5}
   enthalpie_libre_provisoire:=enthalpie_libre;



for i:=1 to  nombre_precipites do present[i-1]:=false;
 {on entame la boucle des essais avec les divers precipites presents ou non
 Par exemple avec 3 precipites, on va essayer successivement:
 0 0 1
 0 1 0
 0 1 1
 1 0 0
 1 0 1
 1 1 0
 1 1 1}

   for i:=2 to puissance_entiere(2,nombre_precipites) do begin
       retenue1:=(present[0]=true);
       present[0]:=not(present[0]);

       if nombre_precipites>1 then for k:=2 to nombre_precipites do begin
       retenue2:=(present[k-1]=true) and retenue1;
       if retenue1 then present[k-1]:=not(present[k-1]);
       retenue1:=retenue2;
       end;

       {modif version 2.5}
       if nombre_precipites>1 then for k:=1 to nombre_precipites do
       if ((not(present[k-1])) and solide_exclu[k-1]) then goto 8080;
        goto 7070;
        8080: continue;
        7070:
       {modif version 2.5}

{ a ce stade, les precipites presents sont connus: on fait le calcul}
   nombre_precipites_actuel:=0;
   for kkk:=1 to nombre_precipites do if present[kkk-1] then inc(nombre_precipites_actuel);
   {on vient de compter le nbe actuel de precipites}
   jjj:=0;  {on va reaffecter les t_n_a_p_e_precipites et les potentiels standards pour ne tenir
   compte que des precipites presents}
   for kkk:=1 to nombre_precipites do if present[kkk-1] then begin
    inc(jjj);
     for iii:=1 to nombre_type_atomes do
     t_n_a_p_e_precipites_p[iii-1,jjj-1]:=t_n_a_p_e_precipites[iii-1,kkk-1];
    potentiels_chimiques_standards_precipites_p[jjj-1]:=potentiels_chimiques_standards_precipites[kkk-1];
t_noms_precipites_p[jjj-1]:=noms_precipites[kkk-1];
tableau_nombre_initial_moles_precipites_p[jjj-1]:=tableau_nombre_initial_moles_precipites[kkk-1];
     end;
   {cest fait; maintenant on peut appeler le calcul ds nbes de moles}
 tentative:=calcule_equilibre_phase_aqueuse_annexe(nombre_solutes,nombre_precipites_actuel,nombre_type_atomes,
 nombre_initial_moles_solvant,tableau_nombre_initial_moles_solutes,tableau_nombre_initial_moles_precipites_p,
 moles_initiales_atomes_0,
t_n_a_p_e_solvant, t_n_a_p_e_solutes,t_n_a_p_e_precipites_p,
nom_solvant,noms_solutes,t_noms_precipites_p,
nombre_moles_equilibre_solvant_p,
nombre_moles_equilibre_solutes_p,nombre_moles_equilibre_precipites_p,
activites_solutes_p,
potentiel_chimique_standard_solvant,
potentiels_chimiques_standards_solutes,potentiels_chimiques_standards_precipites_p,
rayons_solutes_0,
volume,temperature,maxresiduconservationrelatif,
maxresiduactionmasserelatif,max_iter,iter_p,enthalpie_libre_p,debye);


 if tentative then begin
 {on teste le resultat}
 tous_positifs:=true;
 for iii:=1 to  nombre_precipites_actuel do tous_positifs:=
 (tous_positifs and (nombre_moles_equilibre_precipites_p[iii-1]>=0));
 for iii:=1 to  nombre_solutes do tous_positifs:=
 (tous_positifs and (nombre_moles_equilibre_solutes_p[iii-1]>=0));

 if tous_positifs then begin
quotient_ok:=true;
{on verifie si, dans le cas ou il pourrait y avoir d'autres precipites, les quotients de reaction sont tels
que ces precipites n'existent effectivement pas; auquel cas c'est termine}
 if nombre_precipites>nombre_precipites_actuel then begin
{calcul des quotients de reaction}
setlength(quotients_reactions,unit1.reac_0);
for iii:=1 to unit1.reac_0 do begin
quotients_reactions[iii-1]:=0;
for jjj:=1 to unit1.nombre_especes_0 do
if unit1.liste_genre_espece[jjj-1]=solute then
if activites_solutes_p[unit1.indices_solutes[jjj-1]-1]>0 then
quotients_reactions[iii-1]:=quotients_reactions[iii-1]+unit1.coeff_stoechio_0[iii-1,jjj-1]*
ln(activites_solutes_p[unit1.indices_solutes[jjj-1]-1])/ln(10);
end; {du calcul des quotients de reactions}

for iii:=1 to nombre_precipites do
if not(present[iii-1]) then
for jjj:=1 to  unit1.reac_0 do
if   unit1.coeff_stoechio_0[jjj-1,unit1.indices_precipites_inverses[iii-1]-1]<>0 then
begin
quotient_ok:=quotient_ok and
(
((unit1.coeff_stoechio_0[jjj-1,unit1.indices_precipites_inverses[iii-1]-1]>0) and
(quotients_reactions[jjj-1]>unit1.logk_0[jjj-1]))
or
 ((unit1.coeff_stoechio_0[jjj-1,unit1.indices_precipites_inverses[iii-1]-1]<0) and
(quotients_reactions[jjj-1]<unit1.logk_0[jjj-1]))
);

end; {de la boucle des precipites}

end  {du cas ou nombre_precipites>0}
    else quotient_ok:=true;
    end; {de tolus positifs}
 end; {de tentative}


jjj:=0;
for kkk:=1 to nombre_precipites do begin
if present[kkk-1] then begin
inc(jjj);
 nombre_moles_equilibre_precipites_p_p[kkk-1]:=nombre_moles_equilibre_precipites_p[jjj-1];
 end else
 nombre_moles_equilibre_precipites_p_p[kkk-1]:=0;
 end;

if (tentative and tous_positifs and quotient_ok  and
((enthalpie_libre_p<enthalpie_libre) or not (une_solution_trouvee)))   then begin
{on a trouve un resultat meilleur}
une_solution_trouvee:=true;
enthalpie_libre:=enthalpie_libre_p;
iter:=iter_p;
for iii:=1 to nombre_solutes do nombre_moles_equilibre_solutes[iii-1]:=
nombre_moles_equilibre_solutes_p[iii-1];
for iii:=1 to nombre_solutes do activites_solutes[iii-1]:=
activites_solutes_p[iii-1];
nombre_moles_equilibre_solvant:=nombre_moles_equilibre_solvant_p;
jjj:=0;
for kkk:=1 to nombre_precipites do begin
if present[kkk-1] then begin
inc(jjj);
 nombre_moles_equilibre_precipites[kkk-1]:=nombre_moles_equilibre_precipites_p[jjj-1];
 end else
 nombre_moles_equilibre_precipites[kkk-1]:=0;
 end;
{resultat affecte}
   end; {du cas ou le resultat est meilleur}
   end;


   finalize(present);
finalize(nombre_moles_equilibre_solutes_p);
finalize(activites_solutes_p);
finalize(nombre_moles_equilibre_precipites_p);
finalize(t_n_a_p_e_precipites_p);
finalize(potentiels_chimiques_standards_precipites_p);
finalize(t_noms_precipites_p);
finalize(tableau_nombre_initial_moles_precipites_p);
finalize(moles_initiales_atomes_0);
finalize(nombre_moles_equilibre_precipites_p_p);
result:=une_solution_trouvee;
         end;

  begin
  pluspetiteconcentrationsignificative:=1e-20;
  pluspetitlnconcentrationsignificatif:=1e-20;
          end.
