#!/usr/bin/perl

################################################################################
##
##                       ACDC
##          Atmospheric Cluster Dynamics Code
##   by Oona Kupiainen-Määttä and Tinja Olenius 2012-
##
##
##   Table of contents
##   #################
##
##   1. Processing command-line input
##
##   2. Reading the input file
##      2.1 Reading the info on the molecule types
##      2.2 Reading the nucleation rules
##      2.3 Reading the coagulation sink cluster
##      2.4 Reading the cluster types
##      2.5 Adding molecule types for the proton and removed proton if needed
##      2.6 Determining the system size for the loop option
##      2.7 Adding cluster numbers for generic ions if they are used
##      2.8 Adding cluster numbers for other fluxes
##      2.9 Checking which molecule types are used in the system
##
##   3. Dealing with forbidden reactions 
##      and reactions with nonstandard products
##
##   4. Charge balance for generic positive or negative ions
##
##   5. Reading the Delta G file
##      5.1 Reading Delta G (or H and S) for each cluster and possibly hydrates
##      5.2 Calculating hydrate distributions
##
##   6. Making the equations
##      6.1 Looping over the clusters and going through all possible collisions
##      6.2 Save the collision term if the collision can happen
##      6.3 Save the corresponding evaporation if it can happen
##      6.4 External losses
##      6.5 Finding out the number of MCMC coefficients
##      6.6 Time dependent source terms
##      6.7 Reactions inside clusters
##
##   7. Reading the cluster radius file
##
##   8. Starting to print the output files
##      8.1 Cluster properties for Matlab driver and Fortran system file
##      8.2 dC/dt for Fortran
##      8.3 Determining if parameters for ions are used in the Matlab files
##      8.4 dC/dt for Matlab
##      8.5 Fluxes for Matlab
##      8.6 Formation rate for Fortran
##      8.7 Formation rate for Matlab
##      8.8 Arrays for collisions, evaporations and losses for Fortran
##      8.9 Masses, radii and molecular content for the loop version
##
##   9. Loss coefficients
##      9.1 Coagulation sink
##         9.11 Coagulation sink parameterizations
##            9.111 Size-dependent sink of the form A*(d/dref)^B,
##                  where d is the diameter
##            9.112 Size-dependent sink based on a constant concentration
##                  and size of background particles
##         9.12 Coagulation sink from an external user-provided subroutine
##         9.13 Coagulation sink given by one number
##         9.14 Coagulation sink for specific clusters from the command line
##         9.15 Printing out size-dependent sink in dry case
##         9.16 Hydrate average for size-dependent sink
##      9.2 Wall losses
##         9.21 Reading in wall losses for all the clusters from a given file
##         9.22 Wall loss parameterizations
##            9.221 Cloud 4 wall loss parameterization from the Excel file by Jasper Kirkby
##            9.222 Cloud 4 wall loss parameterization from Andreas Kürten
##            9.223 Cloud 4 wall loss parameterization used in the paper by Joao Almeida et al., 2013
##            9.224 Simplified Cloud 4 wall loss parameterization based on the paper by Andreas Kürten et al., 2015
##            9.225 Cloud 3 wall loss parameterization
##            9.226 Diffusion wall loss for a flow tube (originally for the tube of Hanson and Eisele, 2000)
##         9.23 Wall losses given by one number
##            9.231 Ift flow tube wall loss
##            9.232 Other size-independent wall loss
##         9.24 Wall losses for specific clusters from the command line
##         9.25 Printing out size-dependent wall losses in dry case
##         9.26 Hydrate average for size-dependent wall losses
##      9.3 Input sink from an external user-provided subroutine
##         9.31 Input sink for specific clusters from the command line
##
##   10. Collision rates
##      10.1 Reading in rates for specific collisions
##      10.2 Reading in sticking factors
##      10.3 Reading in dipole moments and polarizabilities
##           for collision enhancement factors
##      10.4 Calculating the collision rates
##         10.41 Determining if this collision has been given
##               a fixed rate value in the collision rate file
##         10.42 Printing a function for calculating
##               the collision rate when using loops
##         10.43 Calculating the hard sphere collision rate
##      10.5 Calculating the ion collision enhancement factors
##         10.51 Su and Bowers, 1973
##         10.52 Su and Chesnavich, 1982
##         10.53 Constant enhancement for all collisions
##      10.6 Hydrate averaged collision rate including ion enhancement
##      10.7 Figuring out sticking factors for each collision
##      10.8 Checking if this is an MCMC coefficient
##      10.9 Printing out the collision rates
##
##   11. Evaporation rates
##      11.1 Function for computing evaporation rates when using loops
##			11.11 Evaporation rates from DeltaGs
##			11.12 Evaporation rates from the Kelvin formula
##      11.2 Reading in rates for specific evaporations
##      11.3 Reading in scaling factors for the evaporation rates
##      11.4 Calculating the evaporation rates
##         11.41 Determining if this evaporation has been given
##               a fixed rate value in the evaporation rate file
##         11.42 Calculating the free energy -based evaporation rate
##            11.421 Figuring out scaling factors for each evaporation
##      11.5 Hydrate averaged evaporation rate
##      11.6 Temperature dependent evaporation rate
##      11.7 Printing out the evaporation rates
##
##   12. Printing the ion loss enhancement factors for Fortran
##
##   13. "True" coefficient values for MCMC
##
##   14. Finishing the Matlab driver file
##
##   15. Subroutines
##
################################################################################

# Modules
use warnings;       # Use warnings
use strict;			# All variables must be declared
use Getopt::Long;	# Use command line input
use 5.10.1;         # Perl version
use List::Util qw(max min sum first); # Use some basic functions

my(@comments,@label,%num_from_label,%mol_num_from_name,$lsilent);
my($max_cluster,$string,$iclus,$jclus,$kclus);
my($ncols,$icol,$i,$j,$k,$l,$n,$ii,$jj,$kk,$ll,$jm,$km,$lm,$jc,$kc,$lc,$combined);
my($line,$line2,$max_terms_per_line);
my($recomb_coeff,$mass1,$mass2,$vol1,$vol2,$lmonomer1,$lmonomer2);
my(@temp_array,@temp_array_2);
my($valid,$radius,$string1,$string2,$string3,$string4);
my(@columns);
my($temperature,$imol,$jmol,$kmol,$nmol,$nmol_types);
my($iline,@input_file,$number_of_lines,$nend,$iend,@mass,@density,@psat,@surface_tension,$sigma);
my($temp_val,$temp_val2,$temp_val3,$size_array,@delta_g,@l_no_delta_g_data,$boltz,$Na,$kcal_per_mol_to_J,@evap_coef,$coll_coef_temp);
my($pi,@coll_coef,@sticking_coef,$volume,$mass_conv,$mass_nion,$dens_nion,$mass_pion,$dens_pion,$evap_coef_temp);
my(@lmonomer);
my(@evap_data,$pressure);
my($driver_file_name,$driver_function_name,$input_file_name,$output_file_name,$output_function_name,$ldo_table_out,$include_negative_ion_terms,$include_positive_ion_terms,$disable_coag_sinks,$coag_terms,$coag_terms_in,$disable_wall_terms,$wall_terms,$wall_terms_in,$disable_dilution,$disable_input_sink,$insink_terms,$insink_terms_in,$disable_evap,@disable_evap_only,$free_energy_file_name,$disable_nonmonomers,$disable_nonmonomer_evaps,$enable_rec_nonmonomers,@nonmonomer_collisions_only,@no_derivative_clus,@no_derivative);
my($lfound);
my($disable_excluded,$disable_excluded_ionization,$disable_boundary);
my($cs_term_temp,$wl_term_temp,$found_negative,$found_positive,$diameter,$ion_coll_method);
my($l_use_get_losses);
my($iline2,$iline0);
my(@molecule_name,@neutral_mols,$n_neutral_mols,@charge,@corr_neutral_mol,@corr_negative_mol,@corr_positive_mol,@n_corr_neutral_mol, @n_corr_negative_mol, @n_corr_positive_mol,@lnegative_cluster,@lpositive_cluster,@lnegative, @lpositive,@lneutral_cluster,@lneutral,$proton,$missing_proton,$generic_negative_ions,$generic_positive_ions,$ncharges);
my($corr_mol);
my($max_cluster_number,$nclust_included);
my($wanted_mol,$valid_evap,$valid_coll);
my($flux_file_name,$flux_function_name,$j_file_name,$j_function_name,$input_for_eq,$input_for_eq_C_fun,$input_for_flux,$input_for_flux_temp,$n_generic_neg,$n_generic_pos,$n_flux_out,$n_flux_out_neg,$n_flux_out_pos,$n_flux_out_max,$n_flux_coag,$n_flux_wall,$n_flux_dil,$n_flux_insink,$n_flux_bound,$n_flux_source,$n_flux_rec,$max_n_flux,$size_ind_coef,$l_save_outgoing,$l_save_outgoing_clust,$l_save_coag_per_clust,$size_C_out,$size_C_eqn,$n_coag_per_clust,@range_coag_per_clust);
my($l_all_output,$l_increase_time,$help);
my($first_neg,$first_pos,@n_max_type,@n_max_type_neg,@n_max_type_pos);
my($temperature_inp,$l_change_temperature,$element_name,$lout);
my($l_charge_balance,$generic_positive_ions_corr,$generic_negative_ions_corr);
my(%lines);
my($temp_label,$temp_label2,$label,@temp_composition,$lsame);
my(%nmonomers,$monomer_clus,@n_coll_products);
my(@nucl_rules,@nucl_rules_neg,@nucl_rules_pos,$n_nucl_rules,$n_nucl_rules_neg,$n_nucl_rules_pos,$irule);
my($dip_file_name,@dip_data,$c_mon,$c_clust,@dip,@pol,$nclus,@fcr);
my($nonstandard_reaction_file_name,$l_nonstandard_allowed,$l_nonstand,@nonstandard_reaction_data,@nonstandard_reactions);
my($collision_coef_file_name,@collision_coef_in,@lcoll_coef_in,$evaporation_coef_file_name,@evaporation_coef_in,@levap_coef_in,$wl_coef_file_name);
my($sticking_factor_file_name,$l_sticking_factor,@sticking_factor,$wanted_clus);
my($scale_evap_file_name, $l_scale_evap, @scale_evap_factor,@evap_coef_scale);
my($l_bulk_density,$radius_file_name,@radius_data,@radius_in,$r1,$r2);
my($lnitrate);
my($air_viscosity,$viscosity_N2,$radius_N2,$mass_N2,$D_acid_N2,$D0_factor,$D_factor,$D_to_wl,$tube_radius,$wl_term_0,$tube_radius_in,$tube_pressure_in);
my($exp_loss_coefficient,$exp_loss_exponent,$exp_loss_ref_cluster,$exp_loss_ref_size,$default_monomer,$lfound_several,$lfound_default);
my($bg_concentration,$bg_diameter,$bg_density,$Diff1,$Diff2,$c1,$c2,$Kn);
my($lfortran,$output_file_name_fortran,$system_file_name_fortran,%coef_quad, %coef_quad_form,%coef_lin);
my(%coef_reac,@ind_reac_form,@ind_reac_loss);
my(@ind_quad_loss,@ind_quad_form,@ind_quad_loss_extra,@ind_quad_form_extra, @ind_lin_loss,@ind_lin_form, %l_quad_bound,$l_coll_factor_mcmc_all,$l_coll_factor_mcmc_n_n,$l_coll_factor_mcmc_n_i,$l_coll_factor_mcmc_n_g,$l_coll_factor_mcmc_rec,$l_coll_factor_mcmc_any,$l_q_neg_mcmc,$l_q_pos_mcmc,$l_wl_mcmc,@wl_mcmc_only,$l_mcmc_any,$n_mcmc_coefs, $missing_energies,$missing_fcr,$l_mcmc_coef,@l_special_mcmc_wl,$icoef_wl);
my(@cs_only,@cs_only_hydr,$one_cs_for_all,$one_cs_for_almost_all,@wl_only,@wl_only_hydr,$one_wl_for_all,$one_wl_for_almost_all,@insink_only);
my($icoef_coll,@l_coll_not_used,$nmolecules,@molecules);
my($lhydrate_average,$rh,$pw,$psw,$name_water_def,$name_water,$mass_water,$dens_water,$volume_water,$iwater,$nwaters,$lfound_hydr,$ihydr,$jhydr,$khydr,$nhydr,@lhas_hydr,@delta_g_hydr,@delta_g_temp, @distr,@distr_temp,@distr_temp2,@distr_temp3,$sum,$sum2);
my(@coll_coef_hydr,@evap_coef_hydr,@fcr_hydr,@dip_hydr,@pol_hydr,@coll_coef_eff,@evap_coef_eff,%radius_in_hydr,@cs_coef_hydr,@wl_coef_hydr,@hydrates_str);
my($l_evap_factor_mcmc,$icoef_evap,$ncoef_evap,$ncoef_coll,$ncoef_coll_n_n,$ncoef_coll_n_i,$ncoef_coll_n_g,$ncoef_coll_rec,$ncoef_wl);
my($dil_value,$dil_str,$use_coag_sinks,$use_wall_terms,$use_dilution,$use_input_sink,$include_generic_ions,$no_generic_ions,$include_generic_neg,$include_generic_pos,$no_generic_neg,$no_generic_pos);
my($module_insink,$routine_insink);
my($variable_temp,$variable_cs,$variable_ion_source,$l_variable_parameters,$n_variable_parameters,$cs_value,$cs_value_in,$no_ambient_params_in_syst);
my($tag,$append_to_file_names,$append_to_eq,$append_to_syst,$append_to_subroutine_names,$append_to_eq_names,$append_to_syst_names,$append_to_ext_names,$label_generic_neg, $label_generic_pos,$label_proton,$label_missing_proton,@coef_true);
my(@negative_clusters,@positive_clusters);
my($stopping);
my($iclus_label,$jclus_label,$kclus_label,$disable_useless_collisions,$keep_useless_collisions,$coef_temp,$include_ion_terms,$line_temp,$fcr_temp);
my(%l_quad_nst,@clust_num_of_monomer,$fcs,$fwl,$evap_comment);
my($parameters_in_get_fcr_1,$parameters_in_get_fcr_2, $parameters_in_get_fcr_3,$parameters_in_get_fcr_4);
my(@base_strength,@acid_strength,$l_strength_neutral,$acid_max,$base_max,$l_print_boundary);
my($str_temp,$str_temp_form,$str_temp2,$str_temp3,$str_temp4,$value_string,$coll_string,$hydr_string,$evap_string,$fixed_string,$fcr_string);
my(@cs_cluster,@cs_cluster_neg,@cs_cluster_pos,$use_coag_to_outgoing, $n_coag_on_formed_clusters,$l_coag,$cs_cluster_label,$cs_cluster_neg_label,$cs_cluster_pos_label);
my($keep_boundary_clusters,$max_n_flux_inc_boundary_clusters,@label_inc_boundary_clusters, $kclus_bound, %clus_bound_ind,$lfound_bound,$print_3d_flux);
my(@label_out,@clust_comp_out,$n_comp_out,$n_out_clust,@range_out_clust,@ind_out_clust);
my($l_old_output,$ref,$comp_ok);
my(@clust_comp,@clust_mass,@clust_radius,@clust_volume);
my(@l_can_be_lost_bound,@l_can_evaporate);
my($clust_mass_max,$diameter_max,$mob_diameter_max,$n_at_bound,@clus_at_bound);
my($lloop,$lloop_cs,$lloop_restrict,$lloop_boundary,$nmol_types_used,@nmol_ranges_array,$nmol_ranges_list,$nmol_comp_list,$nmol_ranges_ind,$nmol_ranges_ij_ind,$cluster_from_indices,@cluster_from_indices_array,$monomer_indices,$nmol_cs_list,@source_function,@source_function_clust,@mol_types_used,@mol_names_used,$loop_coll_coef,$loop_evap_coef,$rlim_no_evap,$rlim_no_evap_str,$lloop_j_frac,$lloop_j_tests,$lgrowth_for_j_tests,$c_growth_compound,$c_growth_compound_str,$rlim_growth_compound_str,$lhs_tests);
my($l_jlim,$nlim,$jlim_sizes_list,$l_j_in,$j_in_function);
my($reactions_in_clusters_file,@cluster_reactions,$n_react_in_clust,$l_reac_in_clus);
my($n_react,$n_prod,@comp_react,@comp_prod,$rate_fwd,$rate_bck,@needed_mols,@forbidden_mols);
my($n_reacting_W,$n_formed_W,$n_catalyzing_W,$l_forbidden_W);

################################################################################
################################################################################
##   1. Processing command-line input                                         ##
################################################################################
################################################################################

# All variables beginning with l are treated as logical variables: 1 is true, 0 is false

# These should not be changed
$label_generic_neg='neg';
$label_generic_pos='pos';
$name_water_def='W';

##### Initialize input variables #####

# Output of this Perl script (formats etc.)
$lsilent = 0;
$lfortran = 0;
$l_all_output = 1;
$l_old_output = 0;
$ldo_table_out = 1;
$l_save_outgoing = 0;
$l_save_outgoing_clust = 0;
$l_save_coag_per_clust = 0;
$disable_nonmonomers = 0;
@nonmonomer_collisions_only = ();
$enable_rec_nonmonomers = 0;
$disable_evap = 0;
$disable_nonmonomer_evaps = 0;
$disable_useless_collisions = 1;
$keep_useless_collisions = 0;
$l_print_boundary = 0;
$keep_boundary_clusters = 0;
$disable_boundary = 0;
$print_3d_flux = 0;
@no_derivative_clus = ();
$l_increase_time = 0;

$lloop = 0;
$lloop_cs = 0;
$lloop_restrict = 0;
$lloop_boundary = 0;
$nclust_included = 'nclust';
$loop_coll_coef = 'hard_spheres';
$loop_evap_coef = 'Kelvin';
$rlim_no_evap = '';
$lloop_j_frac = 0;
$l_jlim = 0;
$jlim_sizes_list = '';
$l_j_in = 0;
$j_in_function = '';
$lloop_j_tests = 0;
$lgrowth_for_j_tests = 0;
$c_growth_compound = 1e7; # cm^-3

$driver_file_name = 'driver_acdc.m';
$output_file_name = 'equations_acdc.m';
$output_file_name_fortran = 'acdc_equations.f90';
$system_file_name_fortran = 'acdc_system.f90';
$flux_file_name = 'dofluxes.m';
$j_file_name = 'formationrate.m';
$append_to_file_names = '';
$append_to_eq = '';
$append_to_syst = '';
$append_to_subroutine_names = '';
$append_to_eq_names = '';
$append_to_syst_names = '';
$append_to_ext_names = '';
$tag = '';
$no_ambient_params_in_syst = 0;
$max_terms_per_line = 10;

$l_coll_factor_mcmc_any = 0;
$l_coll_factor_mcmc_all = 0;
$l_coll_factor_mcmc_n_n = 0;
$l_coll_factor_mcmc_n_i = 0;
$l_coll_factor_mcmc_n_g = 0;
$l_coll_factor_mcmc_rec = 0;
$l_q_neg_mcmc = 0;
$l_q_pos_mcmc = 0;
$l_wl_mcmc = 0;
@wl_mcmc_only = ();
$l_evap_factor_mcmc = 0;

$l_change_temperature = 0;

@source_function = ();

# Default input files or variables of this Perl script
$input_file_name = 'input_def.inp';
$free_energy_file_name = 'G_def.txt';
$dip_file_name = 'dip_pol_def.txt';

$radius_file_name = '';
$nonstandard_reaction_file_name = '';
$reactions_in_clusters_file = '';
$l_reac_in_clus = 0;

$collision_coef_file_name = '';
$evaporation_coef_file_name = '';
$sticking_factor_file_name = '';
$sticking_factor[0][0] = 1;
$sticking_factor[1][0] = 1;
$scale_evap_file_name = '';
$scale_evap_factor[0][0] = 0;

# Variables related to external sinks
$disable_coag_sinks = 0;
$disable_wall_terms = 0;
$disable_dilution = 0;
$disable_input_sink = 0;
$use_coag_sinks = 0;
$use_coag_to_outgoing = 0;
$use_wall_terms = 0;
$use_dilution = 0;
$use_input_sink = 0;
@cs_only = ();
@wl_only = ();
@insink_only = ();

$coag_terms_in = '';                # Coagulation losses
$cs_value_in = '';
$cs_value = "1e-3";
$coag_terms = 'exp_loss';			# Options: exp_loss, bg_loss, number in 1/s, external
$exp_loss_coefficient = $cs_value;
$exp_loss_exponent = -1.6;
$exp_loss_ref_cluster = '';
$exp_loss_ref_size = '';
$default_monomer = 'A';
$bg_concentration = 1e3; # cm^-3
$bg_diameter = 100; # nm
$bg_density = 1000; # kg/m^3

$wall_terms_in = '';                # Wall losses
$wl_coef_file_name = '';
$wall_terms = 'CLOUD4_JA';			# Options: cloud4_JA, cloud4_JK, cloud4_AK, cloud4_simple, cloud3, ift, diffusion, number in 1/s
$tube_radius_in = '';
$tube_pressure_in = '';

$dil_value = 9.6e-5;				# Dilution from CLOUD: dil = flow / vol / 60000

$insink_terms_in = '';              # User-defined input sink
$insink_terms = '';
$module_insink = '';
$routine_insink = '';

# Variables related to ions
$include_generic_ions = 1;
$no_generic_ions = 0;
$include_generic_neg = 0;
$include_generic_pos = 0;
$no_generic_neg = 0;
$no_generic_pos = 0;
$l_charge_balance = 0;				# 1 (-1) -> set [pos] ([neg]) to match overall negative (positive) charge, 0 -> use source terms for both
$ion_coll_method = 'Su82';			# Options: Su82, Su73, constant
$fcs = 1;
$fwl = 3.3;
$recomb_coeff = 1.6e-12;

# Variables related to parameters that can be set to have non-fixed values
$l_variable_parameters = 0;
$n_variable_parameters = 0;
$variable_temp = 0;
$variable_cs = 0;
$variable_ion_source = 0;

# Variables related to hydration / equilibrium with respect to a given compound
# Note that while water is the principle compound assumed to be equilibrated at atmospheric conditions, also
# some other compound can be assumed to be in equilibrium by giving as input its name, mass, density and partial pressure
$rh = 0;
$pw = 0;
$name_water=$name_water_def;        # Name used to identify hydrates in the input files for cluster properties
$mass_water=18.02;                  # amu
$dens_water=997.0;                  # kg/m**3


##### Read in the command line input #####

#getopts('d:o:e:f:wit:xcm', \%opts); # for Getopt::Std
GetOptions('help'=>\$help, 'silent'=>\$lsilent, 'fortran'=>\$lfortran, 'all_output|a!'=>\$l_all_output, 'old_output_order|old_output'=>\$l_old_output, 
'disable_nonmonomers|no_nonmonomers|m'=>\$disable_nonmonomers, 'nonmonomer_only|cluster_collisions_only=s' => \@nonmonomer_collisions_only, 
'enable_rec_nonmonomers'=>\$enable_rec_nonmonomers, 'disable_evap|no_evap'=>\$disable_evap, 
'disable_nonmonomer_evaps|no_nonmonomer_evaps|me'=>\$disable_nonmonomer_evaps, 'all_collisions|keep_useless_collisions'=>\$keep_useless_collisions, 'disable_boundary'=>\$disable_boundary, 
'print_boundary'=>\$l_print_boundary, 'keep_boundary_clusters'=>\$keep_boundary_clusters, 'print_3d_flux|flux_3d' => \$print_3d_flux, 
'disable_excluded'=>\$disable_excluded, 'disable_excluded_ionization'=>\$disable_excluded_ionization, 
'save_outgoing'=>\$l_save_outgoing, 'save_outgoing_clust'=>\$l_save_outgoing_clust, 'save_coag_per_clust'=>\$l_save_coag_per_clust, 
'no_derivative_clus|no_eq=s' => \@no_derivative_clus, 'increase_time'=>\$l_increase_time, 
'loop' => \$lloop, 'loop_cs' => \$lloop_cs, 'loop_restrict|restrict' => \$lloop_restrict, 'loop_boundary|boundary' => \$lloop_boundary, 
'loop_coll_coef=s' => \$loop_coll_coef, 'loop_evap_coef=s' => \$loop_evap_coef, 'rlim_no_evap|evaplim=f' => \$rlim_no_evap, 
'loop_j_frac|j_frac' => \$lloop_j_frac, 'jlim=s' => \$jlim_sizes_list, 'j_in' => \$l_j_in, 'j_in_function=s' => \$j_in_function, 
'loop_j_tests' => \$lloop_j_tests, 'growth_for_j_tests' => \$lgrowth_for_j_tests, 'c_growth_compound=f' => \$c_growth_compound, 
'hs_tests|hs_in' => \$lhs_tests, 
'driver_file_name|d=s' => \$driver_file_name, 'output_file_name|o=s' => \$output_file_name,
'system_file_name|syst=s' => \$system_file_name_fortran, 'flux_file_name|f=s' => \$flux_file_name,
'append_to_file_names|append=s'=>\$append_to_file_names, 'append_to_eq=s'=>\$append_to_eq, 'append_to_syst=s'=>\$append_to_syst,
'tag=s'=>\$tag, 'no_ambient_params_in_syst|no_ambient'=>\$no_ambient_params_in_syst,
'append_to_subroutine_names|append_to_subroutines=s'=>\$append_to_subroutine_names,
'append_to_eq_names=s'=>\$append_to_eq_names, 'append_to_syst_names=s'=>\$append_to_syst_names, 'append_to_ext_names=s'=>\$append_to_ext_names,
'coll_coef_mcmc|coll_coef_mcmc_all' => \$l_coll_factor_mcmc_all, 
'coll_coef_mcmc_neutral|coll_coef_mcmc_neutral_neutral|coll_coef_mcmc_n_n' => \$l_coll_factor_mcmc_n_n, 
'coll_coef_mcmc_ion|coll_coef_mcmc_neutral_ion|coll_coef_mcmc_n_i' => \$l_coll_factor_mcmc_n_i, 
'coll_coef_mcmc_charger|coll_coef_mcmc_neutral_charger|coll_coef_mcmc_n_g' => \$l_coll_factor_mcmc_n_g, 
'coll_coef_mcmc_rec' => \$l_coll_factor_mcmc_rec, 'q_neg_mcmc' => \$l_q_neg_mcmc, 'q_pos_mcmc' => \$l_q_pos_mcmc,
'wl_mcmc' => \$l_wl_mcmc, 'wl_mcmc_only=s' => \@wl_mcmc_only, 'evap_coef_mcmc' => \$l_evap_factor_mcmc, 
'temperature|t=s' => \$temperature, 'source_function=s' => \@source_function,
'cluster_set_file_name|cluster_set|c|input_file_name|i=s' => \$input_file_name, 'free_energy_file_name|evap_file_name|e=s' => \$free_energy_file_name, 
'dip_file_name|dip=s' => \$dip_file_name, 'radius_file_name|rad=s' => \$radius_file_name, 
'rh=f' => \$rh, 'pw|peq=f' => \$pw, 'name_water|name_eq=s' => \$name_water, 'mass_water|mass_eq=f' => \$mass_water, 'density_water|density_eq=f' => \$dens_water, 
'nonstandard_reaction_file|nst=s' => \$nonstandard_reaction_file_name, 
'reactions_in_clusters_file|cluster_reaction_file|clust_reac=s'  => \$reactions_in_clusters_file, 
'collision_coef_file_name=s' => \$collision_coef_file_name, 'evaporation_coef_file_name=s' => \$evaporation_coef_file_name,
'sticking_factor_file_name|enhancement_factor_file_name=s' => \$sticking_factor_file_name, 
'sticking_factor|enhancement_factor=f' => \$sticking_factor[0][0], 'sticking_factor_ion_neutral=f' => \$sticking_factor[1][0],
'scale_evap_file_name=s' => \$scale_evap_file_name, 'scale_evap_factor=f' => \$scale_evap_factor[0][0], 
'disable_coag_sinks|disable_coag'=>\$disable_coag_sinks, 'disable_wall_terms|disable_wall_losses|disable_wl'=>\$disable_wall_terms, 
'disable_dilution'=>\$disable_dilution, 'disable_input_sink'=>\$disable_input_sink, 
'use_coag_sinks|use_coag|use_cs'=>\$use_coag_sinks, 'use_wall_terms|use_wall_losses|use_wl'=>\$use_wall_terms, 
'use_dilution|use_dil'=>\$use_dilution, 'use_input_sink|use_insink'=>\$use_input_sink, 
'coag_terms|cs=s'=>\$coag_terms_in, 'cs_value=f'=>\$cs_value_in, 
'exp_loss_coefficient=f' => \$exp_loss_coefficient, 'exp_loss_exponent=f' => \$exp_loss_exponent, 
'exp_loss_ref_cluster=s' => \$exp_loss_ref_cluster, 'exp_loss_ref_size=f' => \$exp_loss_ref_size, 
'bg_concentration|bg_c=f' => \$bg_concentration, 'bg_diameter|bg_d=f' => \$bg_diameter, 'bg_density|bg_rho=f' => \$bg_density, 
'wall_terms|wl=s'=>\$wall_terms_in, 'wl_coef_file_name|wlfile=s'=>\$wl_coef_file_name, 
'flowtube_radius=f' => \$tube_radius_in, 'flowtube_pressure=f' => \$tube_pressure_in, 
'dil_value=f' => \$dil_value, 
'insink_terms|insink=s'=>\$insink_terms_in, 
'cs_only=s' => \@cs_only, 'wl_only=s' => \@wl_only, 'insink_only=s' => \@insink_only, 
'no_generic_ions|no_gen'=>\$no_generic_ions, 'no_generic_neg|no_neg_charger'=>\$no_generic_neg, 'no_generic_pos|no_pos_charger'=>\$no_generic_pos, 
'nitrate'=>\$lnitrate, 'charge_balance|cb=i' => \$l_charge_balance, 'ion_coll_method=s'=> \$ion_coll_method, 'fcs=f' => \$fcs, 'fwl=f' => \$fwl, 
'variable_temp'=>\$variable_temp, 'variable_cs'=>\$variable_cs, 'variable_ion_source'=>\$variable_ion_source);

if(!$l_all_output){
	die "Option noall_output has been disabled since no-one was using it.\n";
}

if($help){
		die "Usage:\tacdc.pl [--options]\n\n
        See the ACDC manual for technical information. Only the features that are not (yet) added to the current manual version are listed below.\n\n
		MCMC options:\n
		\t--evap_coef_mcmc
		\t\tmcmc coefficients for evaporation rates\n
		\t--coll_coef_mcmc_neutral
		\t\tmcmc coefficients for neutral-neutral collision rates\n
		\t--coll_coef_mcmc_ion
		\t\tmcmc coefficients for neutral-ion collision rates (including charger ions)\n
		\t--coll_coef_mcmc_rec
		\t\tmcmc coefficients for ion-ion recombination rates\n
		\t--coll_coef_mcmc_charger
		\t\tmcmc coefficients for neutral-charger ion collision rates\n
		\t--coll_coef_mcmc
		\t\tmcmc coefficients for all collision rates\n
		\t--l_q_neg_mcmc
		\t\tmcmc coefficients for negative charger ion source term\n
		\t--l_q_pos_mcmc
		\t\tmcmc coefficients for positive charger ion source term\n
		\t--l_wl_mcmc
		\t\tmcmc coefficients for wall loss term (same for all clusters, no charge enhancement)\n
		\t--wl_mcmc_only clust
		\t\tuse mcmc wall losses only for cluster 'clust'\n";
}else{
		if(!$lsilent){
            print "\nSee ACDC manual at https://github.com/tolenius/ACDC for help.\n\n";
        }
}

##### Update the input variables after reading the command line #####

### Determining which losses are used ###
if($cs_value_in ne ''){
	$cs_value=$cs_value_in;
	if($coag_terms_in ne ''){
		die "\nGive coagulation losses either as the name of the parameterization (or a single number) or as the variable cs_value, but not both!\n\n";
	}else{
		$coag_terms_in=$cs_value_in;
	}
}
if($variable_cs && $#cs_only>=0){
	for($icol=0;$icol<=$#cs_only;$icol++){
		@columns=split(',',$cs_only[$icol]);
		if($columns[1] ne 0){
			die "\nCannot define fixed coagulation sink values for specific clusters when using a varying sink.\n\n";
		}
	}
}
if($wl_coef_file_name ne ''){
	if($wall_terms_in ne ''){
		die "\nGive wall losses either as the name of the parameterization (or a single number) or as the name of the file containing the losses, but not both!\n\n";
	}else{
		$wall_terms_in='wlfile';
	}
}
$str_temp = "Not using coagulation sinks.\n";
$str_temp2 = "Not using wall losses.\n";
$str_temp3 = "Not using dilution.\n";
$str_temp4 = "Not using additional user-defined sinks.\n";
if(($use_coag_sinks+$use_wall_terms+$use_dilution+$use_input_sink+$variable_cs+$l_wl_mcmc)>0 || $coag_terms_in ne '' || $wall_terms_in ne '' || $insink_terms_in ne '' || $#cs_only>=0 || $#wl_only>=0 || $#insink_only>=0 || $#wl_mcmc_only>=0){
	if(($disable_coag_sinks+$disable_wall_terms+$disable_dilution+$disable_input_sink)>0){
		die "\nSpecify which losses to use or which losses to disable, but not both!\n\n";
	}
	if($use_coag_sinks==0 && $variable_cs==0 && $coag_terms_in eq '' && $#cs_only<0){
		$disable_coag_sinks = 1;
	}elsif($coag_terms_in eq '' && $#cs_only>=0){
		$coag_terms_in = '0.0';
		$str_temp = "Using coagulation sinks (but only for some clusters).\n";
	}else{
		$str_temp = "Using coagulation sinks.\n";
	}
	if($use_wall_terms==0 && $l_wl_mcmc==0 && $#wl_mcmc_only<0 && $wall_terms_in eq '' && $#wl_only<0){
		$disable_wall_terms = 1;
	}elsif($wall_terms_in ne '' && $l_wl_mcmc==1){
		die "\nSpecify your wall loss term or use an mcmc coefficient for it, but not both!\n\n";
	}elsif($wall_terms_in eq '' && $#wl_only>=0){
		$wall_terms_in = '0.0';
		$str_temp2 = "Using wall losses (but only for some clusters).\n";
	}elsif($#wl_only>=0 && ($l_wl_mcmc || $#wl_mcmc_only>=0)){
		die "wl_only cannot be used together with mcmc wall losses";
	}else{
		$str_temp2 = "Using wall losses.\n";
	}
	if($use_dilution==0){
		$disable_dilution = 1;
	}else{
		$str_temp3 = "Using dilution.\n";
	}
    if($use_input_sink==0 && $insink_terms_in eq '' && $#insink_only<0){
		$disable_input_sink = 1;
    }elsif($insink_terms_in eq '' && $#insink_only>=0){
        die "\nFor now, the user-defined sink must be a subroutine; only single values for some clusters cannot be given\n\n";
    }elsif(!$lfortran){
        die "\nThe user-defined sink option works only with the Fortran version, for now.\n\n";
    }else{
		$str_temp4 = "Using additional user-defined sinks.\n";
	}
}elsif(($disable_coag_sinks+$disable_wall_terms+$disable_dilution+$disable_input_sink)==0){
	$disable_coag_sinks = 1;
	$disable_wall_terms = 1;
	$disable_dilution = 1;
    $disable_input_sink = 1;
}else{
	if($disable_coag_sinks==0){
		$str_temp = "Using coagulation sinks.\n";
	}
	if($disable_wall_terms==0){
		$str_temp2 = "Using wall losses.\n";
	}
	if($disable_dilution==0){
		$str_temp3 = "Using dilution.\n";
	}
    if($disable_input_sink==0){
		$str_temp4 = "Using additional user-defined sinks.\n";
	}
}
if(!$lsilent){
    print $str_temp;
    print $str_temp2;
    print $str_temp3;
    print $str_temp4;
}
if($coag_terms_in ne ''){
	$coag_terms = $coag_terms_in;
}
if($wall_terms_in ne ''){
	$wall_terms = $wall_terms_in;
}
if($insink_terms_in ne ''){
	$insink_terms = $insink_terms_in;
}
if(&is_pos_number($coag_terms)){
	if($#cs_only>=0){
		$one_cs_for_all = 0;
		$one_cs_for_almost_all = 1;
	}else{
		$one_cs_for_all = 1;
		$one_cs_for_almost_all = 0;
	}
}else{
	$one_cs_for_all = 0;
	$one_cs_for_almost_all = 0;
}
if($l_wl_mcmc==1 || &is_pos_number($wall_terms) || $wall_terms =~ m/ift/i){
	if($#wl_mcmc_only>=0){
		$one_wl_for_all = 0;
		$one_wl_for_almost_all = 1;
	}elsif($#wl_only>=0){
		$one_wl_for_all = 0;
		$one_wl_for_almost_all = 1;
	}else{
		$one_wl_for_all = 1;
		$one_wl_for_almost_all = 0;
	}
}else{
	$one_wl_for_all = 0;
	$one_wl_for_almost_all = 0;
}
# Determining if we are using some losses that go into get_losses
if((!$disable_coag_sinks && (!$one_cs_for_all || !$variable_cs)) || !$disable_wall_terms || ($lfortran && !$disable_dilution) || !$disable_input_sink){
	$l_use_get_losses = 1;
}else{
	$l_use_get_losses = 0;
}
# Unit conversions etc. related to some of the loss options
if(!$disable_coag_sinks){
    if($coag_terms =~ m/^exp_loss$/i && $exp_loss_ref_size ne ''){
        $exp_loss_ref_size *= 0.5*1e-9; # diameter -> radius, nm -> m
    }elsif($coag_terms =~ m/^bg_loss$/i){
        $bg_concentration *= 1e6; # cm^-3 -> m^-3
        $bg_diameter *= 1e-9; # nm -> m
    }
}
if(!$disable_dilution){
	$dil_str = sprintf('%.14e',$dil_value);
	if($lfortran){
		$dil_str =~ s/e/d/;
	}
}
if(!$disable_input_sink){
    # Input for the user-defined sink is either "$routine_insink" or "$routine_insink,$module_insink"
    @temp_array=split(',',$insink_terms);
    $routine_insink = $temp_array[0];
    if($#temp_array>0){
        $module_insink = $temp_array[1];
    }
}

### Determining if all generic ions are disabled ###
if($no_generic_ions){
	$include_generic_ions = 0;
	$include_generic_neg = 0;
	$include_generic_pos = 0;
	$no_generic_neg = 1;
	$no_generic_pos = 1;
    if(!$lsilent){
        print "Not using generic ions.\n";
    }
}

### Settings related to disabled cluster-cluster processes
if($disable_nonmonomers && !$disable_nonmonomer_evaps){
	$disable_nonmonomer_evaps = 1;
}
# Determining if cluster-cluster processes are allowed only when recombination is involved ###
if($enable_rec_nonmonomers && !$disable_nonmonomers){
	$disable_nonmonomers = 1;
    if(!$lsilent){
        print "Disabling cluster-cluster processes except for collisions involving recombination.\n";
    }
}

### Checking the option for disabling the printing out of some derivatives ###
if($#no_derivative_clus>=0 && !$lfortran){
	die "The option to not print out derivatives is only for the Fortran version, for now.";
}

### Determining if the equations are written as loops ###
if($lloop_cs || $lloop_restrict || $lloop_boundary){
	$lloop = 1;
}
if($lloop_boundary){
	$lloop_restrict = 1;
}
if($lloop_restrict){
	$nclust_included = 'nclust_inc';
}
# Disabling cluster fissions if the Kelvin evaporation is used in the loop mode
if($lloop && $loop_evap_coef =~ m/^Kelvin$/i && (!$disable_evap || !$disable_nonmonomer_evaps)){
	$disable_nonmonomer_evaps = 1;
    if(!$lsilent){
        print "Disabling cluster fissions.\n";
    }
}

### Determining if reactions in clusters are used ###
if($reactions_in_clusters_file ne ''){
	$l_reac_in_clus = 1;
	if($lfortran){
		die "\nThe reactions in clusters option hasn't yet been implemented to the Fortran version.\n\n";
	}
	if($variable_temp){
		die "\nThe reactions in clusters option cannot be used with a variable temperature.\n\n";
	}
}

### Determinig if the net formation fluxes over some specific size limits are recorded ###
# (works only for the loop mode)
if($jlim_sizes_list ne ''){
	if(!$lloop){
		die "\nSaving the fluxes over the given size limits is a feature of the loop mode\n";
	}else{
		$l_jlim = 1;
		@temp_array=split(',',$jlim_sizes_list);
		$nlim = $#temp_array + 1;
		if($lfortran){
			for(@temp_array){
				if($_ =~ m/\./){
					$_ .= "d0";
				}else{
					$_ .= ".d0";
				}
			}
			$jlim_sizes_list = join(',',@temp_array);
		}
	}
}

### Determinig if the distribution is simulated only above some "formation size", for which a source function is used ###
# (works only for the one-component loop mode)
if($j_in_function ne ''){
	$l_j_in = 1;
}
if($l_j_in){
	if(!$lloop){
		die "\nUsing an input formation rate for some specific size is a feature of the loop mode\n";
	}
	# Add the "formation size" to the list of source functions
	$str_temp = "n_j_in";
	if($j_in_function ne ''){
		$str_temp .= ",$j_in_function";
	}
	push(@source_function,$str_temp);
}
# This is only used in the J validation study (on Triolith/Fafner), and it
# (1) prints the output as in the tests for J(t) vs. J(steady-state)/J(extrapolated steady-state) etc.,
# [(2) uses the specific modules etc. to get the bg concentration,] -> this is now a default for the loop mode
# (3) considers evaporation only up to a specific size,
# (4) adds the irreversible condensation of a so-called implicit growth compound
#     to particles larger than a specific threshold size
if($lloop_j_tests){
	print "\nPrinting the output for the J validation tests!\n";
	$lgrowth_for_j_tests = 1;
}
if($lgrowth_for_j_tests){
	$rlim_no_evap = 0.75; # nm

	$rlim_growth_compound_str = '1.5d0*1.d-9'; # nm -> m
	
	$c_growth_compound *= 1e6; # cm^-3 -> m^-3
	$c_growth_compound *= 0.5; # assuming two different masses (each have the same number concentration so that Ctot=$c_growth_compound)
	$c_growth_compound_str = sprintf('%.14e',$c_growth_compound);
	$c_growth_compound_str =~ s/e/d/;
	#$c_growth_compound_str = '5.d6*1.d6'; # cm^-3 -> m^-3
	
	print "Using implicit 'growth compounds' with C = $c_growth_compound_str m^-3,\n";
	print "that condense onto particles r >= $rlim_growth_compound_str m,\n";
	print "also restricting evaporation to sizes of r < $rlim_no_evap nm\n";
}

### Determining if a limit size for evaporation is used
if($rlim_no_evap !~ /^\s*$/){
	if(!$lloop){
		die "\nOption --rlim_no_evap works only for the loop mode.\n\n";
	}
	$rlim_no_evap_str = sprintf('%.14e',$rlim_no_evap*1e-9); # nm -> m
	$rlim_no_evap_str =~ s/e/d/;
}

### Determining if useless collisions are kept in the output files ###
if($keep_useless_collisions == 1){
	$disable_useless_collisions = 0;
}

### Determining if clusters outside the system boundaries are tracked ###
# (works only for the Matlab version)
if($keep_boundary_clusters && $lfortran){
	die "\nSaving the boundary fluxes is a feature of the Matlab version\n";
}

### Determining if outgoing flux per outgrown cluster is tracked ###
# (works only for the Fortran version)
if($l_save_outgoing_clust){
    $l_save_outgoing = 1;
    if(!$lfortran){
        die "\nSaving the concentration of outgoing flux for each outgrown cluster is a feature of the Fortran version\n";
    }
}

### Determining if coagulation losses per cluster are tracked ###
# (works only for the Fortran version)
if($l_save_coag_per_clust){
    if(!$lfortran){
        die "\nSaving the concentration lost by coagulation scavenging for each cluster is a feature of the Fortran version\n";
    }
    if(!$l_save_outgoing){
        $l_save_outgoing = 1; # Doesn't make much sense to include coag. per cluster but no "dynamic" formation rate
        print "\nTurning on the option to save the outgoing concentrations, as also the option to save coagulation for each cluster is on\n";
        print "(Cannot see why they would not be used together)\n";
    }
}

### Determining if bulk densities are used ###
if($radius_file_name eq ''){
	$l_bulk_density = 1;
}else{
	$l_bulk_density = 0;
}

### Names of the output files ###
if($lfortran){
	if($output_file_name ne 'equations_acdc.m'){
		$output_file_name_fortran = $output_file_name;
	}
}
# Appending an ending to all output file names
if($append_to_file_names ne ''){
	if($lfortran){
        if($append_to_eq ne '' || $append_to_syst ne ''){
            die "\nGive file name suffices either for all output files, or separately for different Fortran files, but not both!\n\n";
        }
        $append_to_eq=$append_to_file_names;
        $append_to_syst=$append_to_file_names;
	}else{
		$driver_file_name =~ s/\.m$/$append_to_file_names\.m/;
		$output_file_name =~ s/\.m$/$append_to_file_names\.m/;
		$flux_file_name =~ s/\.m$/$append_to_file_names\.m/;
		$j_file_name =~ s/\.m$/$append_to_file_names\.m/;
	}
}
if($append_to_eq ne ''){
    $output_file_name_fortran =~ s/\.f90$/$append_to_eq\.f90/;
}
if($append_to_syst ne ''){
    $system_file_name_fortran =~ s/\.f90$/$append_to_syst\.f90/;
}
# Extracting the Matlab function names from the files names (removing the .m ending)
if(!$lfortran){
	$driver_function_name = $driver_file_name;
	$driver_function_name =~ s/\.\S*$//;
	
	$output_function_name = $output_file_name;
	$output_function_name =~ s/\.\S*$//;
	
	$flux_function_name = $flux_file_name;
	$flux_function_name =~ s/\.\S*$//;
	
	$j_function_name = $j_file_name;
	$j_function_name =~ s/\.\S*$//;
}

### Possible suffices in subroutine names ###
if($append_to_subroutine_names ne ''){
    if($append_to_eq_names ne '' || $append_to_syst_names ne '' || $append_to_ext_names ne ''){
        die "\nGive subroutine name suffices either for all subroutines, or separately for subroutines in different Fortran files, but not both!\n\n";
    }
    $append_to_eq_names=$append_to_subroutine_names;
    $append_to_syst_names=$append_to_subroutine_names;
    $append_to_ext_names=$append_to_subroutine_names;
}

### Tag for labeling the simulation system and/or set-up ###
if($tag ne ''){
    if(!$lfortran){
        die "\nThe tag option is only for Fortran (for easily recognizing the system during run) - for Matlab, you might want to use file name suffices\n\n";
    }
    $tag = "'$tag'";
}

### MCMC stuff ###
if($l_coll_factor_mcmc_all){
	$l_coll_factor_mcmc_n_n = 1;
	$l_coll_factor_mcmc_n_i = 1;
	$l_coll_factor_mcmc_rec = 1;
}
if($l_coll_factor_mcmc_n_i){
	$l_coll_factor_mcmc_n_g = 1;
}

if($l_coll_factor_mcmc_n_n || $l_coll_factor_mcmc_n_i || $l_coll_factor_mcmc_rec || $l_coll_factor_mcmc_n_g){
	$l_coll_factor_mcmc_any = 1;
}
if($l_coll_factor_mcmc_any || $l_evap_factor_mcmc || $l_q_neg_mcmc || $l_q_pos_mcmc || $l_wl_mcmc || $#wl_mcmc_only>=0){
	$l_mcmc_any = 1;
	$ncoef_coll = 0;
	$ncoef_coll_n_n = 0;
	$ncoef_coll_n_i = 0;
	$ncoef_coll_n_g = 0;
	$ncoef_coll_rec = 0;
	$ncoef_evap = 0;
	$ncoef_wl = 0;
	if($lfortran == 0){
		die "\nThe MCMC coefficients work only with the fortran version!\n\n";
	}
	if($variable_temp){
		die "\nThe MCMC coefficients cannot be combined with a varying temperature!\n\n";
	}
	if(($sticking_factor[0][0] != 1) || ($sticking_factor[1][0] != 1) || ($sticking_factor_file_name ne '')){
		die "\nThe MCMC coefficients cannot be combined with other sticking factors!\n\n";
	}
}

### Parameters with non-fixed values ###
if($variable_temp || $variable_cs || $variable_ion_source){
	$l_variable_parameters = 1;
	$n_variable_parameters = $variable_temp+$variable_cs+2*$variable_ion_source;
}
if($variable_cs){
	if(!$lfortran){
		die "\nThe --variable_cs option works only with the Fortran version.\n\n";
	}
}
if($variable_ion_source){
	if(!$lfortran || $lloop){
		die "\nThe --variable_ion_source option works only with the Fortran version in the small set mode.\n\n";
	}
	if($no_generic_neg || $no_generic_pos){
		die "\nThe --variable_ion_source option works only if both charger ions are enabled.\n\n";
	}
}

### Constants and properties of generic compounds (charger ions, water...) ###

# Values for constants
$boltz=1.3806504e-23; # J/K
$pi=3.14159265359;
$Na=6.02214179e23;
$mass_conv=1.0/$Na/1000.0; # convert g/mol to kg
$kcal_per_mol_to_J=4.184*1000.0/$Na;

# Properties of charger ions
if($lnitrate){
	# nitrate ion dimer
	$mass_nion=125*$mass_conv; # kg
	$dens_nion=1512.9; # liquid density in kg/m**3
}else{
	# the generic negative ion now has the mass and density of an O2 molecule
	$mass_nion=32.00*$mass_conv; # kg
	$dens_nion=1141.0; # liquid density in kg/m**3
}
# the generic positive ion now has the mass and density of a (charged) water molecule
$mass_pion=19.02*$mass_conv; # kg
$dens_pion=997.0; # kg/m**3

# Use equilibrium hydrate distributions?
if($rh > 0 || $pw > 0){
    if($rh > 0 && $pw > 0){
        die "\nUse either --rh (in %) or --pw (in Pa) for water vapor concentration to consider effects of hydration, but not both\n\n";
    }
	if($variable_temp==1){
		die "\nThe option --variable_temp is not compatible with hydrate distributions!\n\n";
	}
    $lhydrate_average=1;
}else{
	$lhydrate_average=0;
}

# Determine if evaporations are disabled, and read in the temperature (use it also for the hydrate distribution calculations)
if(($disable_evap && !$lhydrate_average) && !$variable_temp){
	if(!(defined $temperature)){
		die "\nYou must give the temperature (for the collision coefficients) if evaporations are disabled.\n\n";
	}
}elsif( -f $free_energy_file_name){
	
	# Read in the temperature
	open(GFILE, "<$free_energy_file_name") || die "\nCould not open the delta G file $free_energy_file_name\n\n";
	chomp(@evap_data=<GFILE>);
	# the first line has the pressure in Pa, and the second one has the temperature
	if(&is_pos_number($evap_data[1])){
		$temperature_inp=$evap_data[1];
		if ($temperature && ($temperature != $temperature_inp)){
            if(!$lsilent){
                print "Converting thermodynamics data from temperature $temperature_inp K to $temperature K.\n";
            }
			$l_change_temperature = 1;
		}else{
			$temperature = $temperature_inp;
		}
	}else{
		die "\nSecond line of $free_energy_file_name has to be the reference temperature, in K.\n\n";
	}
	close(GFILE);
}elsif(!(defined $temperature)){
	$temperature = 298.15;
}

# Properties of water for hydrate distribution calculations
$mass_water=$mass_water*$mass_conv; # amu -> kg
$volume_water=$mass_water/$dens_water;

# Saturation vapor pressure, needed for obtaining the absolute partial pressure when RH is given as input
# Reference: Arnold Wexler: 'Vapor Pressure Formulation for Water in Range 0 to 100 °C. A Revision'. JOURNAL OF RESEARCH of the National Bureau of Standards, 80A, 5-6, 775-785, 1976
$psw = exp(-2991.2729*$temperature**(-2)-6017.0128/$temperature+18.87643854-0.028354721*$temperature+0.17838301e-4*$temperature**2-0.84150417e-9*$temperature**3+0.44412543e-12*$temperature**4+2.858487*log($temperature)); # Pa
# Previously used formula from Hanna Vehkamäki: Classical Nucleation Theory in Multicomponent Systems, DOI 10.1007/b138396, Springer, 2006
#$psw = exp(77.344913-7235.4247/$temperature-8.2*log($temperature)+0.0057113*$temperature);

if($rh > 0){
    $pw = $rh/100*$psw;
    if(!$lsilent && ($name_water ne $name_water_def)){
        print "\nAssuming the saturation vapor pressure of water for compound $name_water;\n";
        print "if this is not correct, give the concentration of $name_water as absolute vapor pressure and not as RH\n\n";
    }
}elsif($pw > 0){
    $rh = $pw/$psw*100;
    if(!$lsilent && ($name_water ne $name_water_def)){
        print "\nRH information obtained for compound $name_water assuming the saturation vapor pressure of water;\n";
        print "(RH is only printed out for information, and only the absolute vapor pressure is used in calculations)\n\n";
    }
}


################################################################################
################################################################################
##   2. Reading the input file                                                ##
################################################################################
################################################################################


######################################################################
### This reads in the input file, which has a listing of all the
### different cluster compositions, using a compact notation...for example,
### s	b   a   d
### 0-5  0   1   0
### is a series of six clusters with one ammonia, 0 ions, 0 dimethylamines, and 0-5 SA molecules.
### This neatly divides the output file into rows, which makes it more readable.
### A row is a grouping of clusters where the number of ions, ammonias, and DMAs
### are all constant.
### Any lines beginning with # are ignored.
######################################################################



$max_cluster=0;  #this is the number of the cluster
# maximum amounts of different kinds of molecules (for any cluster), separately for neutral, neg. and pos. clusters 
@n_max_type = (0);
@n_max_type_pos = (0);
@n_max_type_neg = (0);
@clust_comp = ([0]);
@temp_array = ();
# molecule numbers of neutral molecules
@neutral_mols = ();
$n_neutral_mols = 0;
# logical telling if acid and/or base strengths are defined for neutral molecules
$l_strength_neutral = 0;

# Arrays to save nucleation criteria and their sizes
$n_nucl_rules = 0;
$n_nucl_rules_neg = 0;
$n_nucl_rules_pos = 0;

open(INP, "<$input_file_name") || die "\nCould not open input file $input_file_name\n\n";
chomp(@input_file=<INP>); # find out how many molecules we have
close(INP);

$number_of_lines=$#input_file;
@columns=split(' ',$input_file[0]); # first line should be e.g. '#   sulphuric_acid   bisulphate ...', basically the names of the molecules 
if($columns[0] eq '#'){
	shift(@columns);
}
$nmol_types=$#columns+1;

for($imol=0;$imol<$nmol_types;$imol++){
	push(@n_max_type,0);
	push(@n_max_type_neg,0);
	push(@n_max_type_pos,0);
	$charge[$imol] = 0;
	$l_can_evaporate[$imol] = 1;
	$l_can_be_lost_bound[$imol] = 1;
}
$found_negative=0; # changes to true if we find a cluster with a negative ion in it
$found_positive=0; # changes to true if we find a cluster with a positive ion in it

# Arrays for the indices of negative and positive clusters
@negative_clusters=();
@positive_clusters=();

# Number in the cluster composition array for proton (positive hydrogen ion)
$proton=-1;
# Number in the cluster composition array for missing_proton (removed from an acid to charge it negatively)
$missing_proton=-1;
# Number of actual molecule types (monomers) including both neutral and charged molecules (proton/missing proton not counted as a molecule)
$nmolecules = 0;
# Number of charging states
$ncharges = 1; # neutral state always exists

# Keep track of the highest acid and base strength, so we can give reasonable values for the proton and missing proton.
$acid_max = 0;
$base_max = 0;

for($iline=1;$iline <= $number_of_lines;$iline++){
	$line=$input_file[$iline];
	next if($line =~ /^\s*$/);
	@columns=split(' ',$line);
	next if($columns[0] =~ /^\#/);

################################################################################
################################################################################
##      2.1 Reading the info on the molecule types                            ##
################################################################################
################################################################################

	if($#columns < $nmol_types-1){
		die("Can't understand line ".($iline+1)." ($line) of input file - too few columns.\n");
	}else{
		
		# the name labels of all the molecules
		if($input_file[$iline] =~ /name/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$molecule_name[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$mol_num_from_name{$columns[$nend+1-$iend]}=$nmol_types-$iend;
				$iend++;
			}

		# the charges of all the molecules
		}elsif($input_file[$iline] =~ /charge/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$charge[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
			for($imol=0;$imol<$nmol_types;$imol++){
				die "\nCharge should be 0, -1 or 1!\n\n" unless($charge[$imol] == -1 || $charge[$imol] == 0 || $charge[$imol] == 1);
                
				# Default values for corresponding molecules and ions
                $corr_neutral_mol[$imol] = '';
                $corr_negative_mol[$imol] = '';
                $corr_positive_mol[$imol] = '';
                $n_corr_neutral_mol[$imol] = -1;
                $n_corr_negative_mol[$imol] = -1;
                $n_corr_positive_mol[$imol] = -1;
                
				# If this is the proton, let's save the molecule number for it
				if($charge[$imol] == 1){
					$proton=$imol;
				}
			}
		
		# the corresponding neutral molecules for the ions
		}elsif($input_file[$iline] =~ /corresponding neutral molecule/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$imol = -1;
				if($columns[$nend+1-$iend] eq '-'){
					$corr_neutral_mol[$nmol_types-$iend]='';
				}else{
					$corr_neutral_mol[$nmol_types-$iend]=$columns[$nend+1-$iend];
					if(exists $mol_num_from_name{$corr_neutral_mol[$nmol_types-$iend]}){
						$imol=$mol_num_from_name{$corr_neutral_mol[$nmol_types-$iend]};
					}
				}
				$n_corr_neutral_mol[$nmol_types-$iend] = $imol;
				$iend++;
			}


		# the corresponding positive ions for bases
		}elsif($input_file[$iline] =~ /corresponding positive ion/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$imol = -1;
				if($columns[$nend+1-$iend] eq '-'){
					$corr_positive_mol[$nmol_types-$iend]='';
				}else{
					$corr_positive_mol[$nmol_types-$iend]=$columns[$nend+1-$iend];
					if(exists $mol_num_from_name{$corr_positive_mol[$nmol_types-$iend]}){
						$imol=$mol_num_from_name{$corr_positive_mol[$nmol_types-$iend]};
					}
				}
				$n_corr_positive_mol[$nmol_types-$iend] = $imol;
				$iend++;
			}

			# If we want to do the table output, we need to know if the first molecule has a positive form.
			if($ldo_table_out){ 
				$first_pos = -1;
				if(length($corr_positive_mol[0])>0){
					if(exists $mol_num_from_name{$corr_positive_mol[0]}){
						$first_pos = $mol_num_from_name{$corr_positive_mol[0]};
					}
				}
			}

		# the corresponding negative ions for acids
		}elsif($input_file[$iline] =~ /corresponding negative ion/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$imol = -1;
				if($columns[$nend+1-$iend] eq '-'){
					$corr_negative_mol[$nmol_types-$iend]='';
				}else{
					$corr_negative_mol[$nmol_types-$iend]=$columns[$nend+1-$iend];
					if(exists $mol_num_from_name{$corr_negative_mol[$nmol_types-$iend]}){
						$imol=$mol_num_from_name{$corr_negative_mol[$nmol_types-$iend]};
					}
				}
				$n_corr_negative_mol[$nmol_types-$iend] = $imol;
				$iend++;
			}

			# If we want to do the table output, we need to know if the first molecule has a negative form.
			if($ldo_table_out){ 
				$first_neg = -1;
				if(length($corr_negative_mol[0])>0){
					if(exists $mol_num_from_name{$corr_negative_mol[0]}){
						$first_neg = $mol_num_from_name{$corr_negative_mol[0]};
					}
				}
			}
		
		# the masses of all the molecules
		}elsif($input_file[$iline] =~ /mass \[\S+\]/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$mass[$nmol_types-$iend]=$columns[$nend+1-$iend]*$mass_conv; # convert to kg
				if($mass[$nmol_types-$iend] < 0){
					$missing_proton=$nmol_types-$iend;
				}
				$iend++;
			}

		# the densities of all the molecules
		}elsif($input_file[$iline] =~ /density \[\S+\]/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$density[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
			
		# the saturation vapor pressures of all the pure compounds
		# (optional)
		}elsif($input_file[$iline] =~ /saturation vapor pressure \[\S+\]/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$psat[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
			
		# the surface tensions of all the pure compounds
		# (optional)
		}elsif($input_file[$iline] =~ /surface tension \[\S+\]/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$surface_tension[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}

		# the acidities of all the molecules
		# (-1 = base, 0 = neither acid or base, 1 = weak acid, 2 = stronger acid, 3 = even stronger acid, ...)
		}elsif($input_file[$iline] =~ /acid/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$acid_strength[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$acid_max = max($acid_max,$acid_strength[$nmol_types-$iend]);
				$iend++;
			}

		# the basicities of all the molecules
		# (-1 = acid, 0 = neither acid or base, 1 = weak base, 2 = stronger base, 3 = even stronger base, ...)
		}elsif($input_file[$iline] =~ /base/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$base_strength[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$base_max = max($base_max,$base_strength[$nmol_types-$iend]);
				$iend++;
			}
		
		
		# can this molecule evaporate ...
		}elsif($input_file[$iline] =~ /can be lost/i || $input_file[$iline] =~ /can evaporate/i){
			
			# ... at all ...
			if($input_file[$iline] !~ /bound/i){
				$nend=$#columns;
				$iend=1;
				while($iend <= $nmol_types){
					$l_can_evaporate[$nmol_types-$iend]=$columns[$nend+1-$iend];
					$iend++;
				}
			}else{
			# ... and when bringing clusters back to the boundary
				$nend=$#columns;
				$iend=1;
				while($iend <= $nmol_types){
					$l_can_be_lost_bound[$nmol_types-$iend]=$columns[$nend+1-$iend];
					$iend++;
				}
			}

################################################################################
################################################################################
##      2.2 Reading the nucleation rules                                      ##
################################################################################
################################################################################

		# the "nucleation criteria" for neutrals
		}elsif($input_file[$iline] =~ /out neutral/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$nucl_rules[$n_nucl_rules][$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
			$n_nucl_rules++;

		# the "nucleation criteria" for negatives
		}elsif($input_file[$iline] =~ /out negative/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$nucl_rules_neg[$n_nucl_rules_neg][$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
			$n_nucl_rules_neg++;

		# the "nucleation criteria" for positives
		}elsif($input_file[$iline] =~ /out positive/i){

			$nend=$#columns;
			$iend=1;
			while($iend <= $nmol_types){
				$nucl_rules_pos[$n_nucl_rules_pos][$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
			# keeping track of the maximum number that the 1st molecule can have in negative clusters of the system
			$n_nucl_rules_pos++;

################################################################################
################################################################################
##      2.3 Reading the coagulation sink cluster                              ##
################################################################################
################################################################################

		}elsif($input_file[$iline] =~ /coag/i && $input_file[$iline] =~ /neg/i){
			$use_coag_to_outgoing = 1;
			$nend=$#columns;
			$iend=1;
			if(defined $cs_cluster_neg[0]){
				die "You can only have one negative coagulation sink cluster.\n";
			}
			@cs_cluster_neg = ();
			while($iend <= $nmol_types){
				$cs_cluster_neg[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
		}elsif($input_file[$iline] =~ /coag/i && $input_file[$iline] =~ /pos/i){
			$use_coag_to_outgoing = 1;
			$nend=$#columns;
			$iend=1;
			if(defined $cs_cluster_pos[0]){
				die "You can only have one positive coagulation sink cluster.\n";
			}
			@cs_cluster_pos = ();
			while($iend <= $nmol_types){
				$cs_cluster_pos[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
		}elsif($input_file[$iline] =~ /coag/i && $input_file[$iline] =~ /neutr/i){
			$use_coag_to_outgoing = 1;
			$nend=$#columns;
			$iend=1;
			if(defined $cs_cluster[0]){
				die "You can only have one neutral coagulation sink cluster.\n";
			}
			@cs_cluster = ();
			while($iend <= $nmol_types){
				$cs_cluster[$nmol_types-$iend]=$columns[$nend+1-$iend];
				$iend++;
			}
		}elsif($input_file[$iline] =~ /coag/i){
			if(!$lloop){
				$use_coag_to_outgoing = 1;
			}else{
				$lloop_cs = 1;
			}
			$nend=$#columns;
			$iend=1;
			@temp_array = ();
			$i = 0;
			while($iend <= $nmol_types){
				$temp_array[$nmol_types-$iend]=$columns[$nend+1-$iend];
				if($temp_array[$nmol_types-$iend]>0 && $charge[$nmol_types-$iend] < 0){
					$i -= $temp_array[$nmol_types-$iend];
				}elsif($temp_array[$nmol_types-$iend]>0 && $charge[$nmol_types-$iend] > 0){
					$i += $temp_array[$nmol_types-$iend];
				}
				$iend++;
			}
			if($i==0){
				if(defined $cs_cluster[0]){
					die "You can only have one neutral coagulation sink cluster.\n";
				}
				@cs_cluster = @temp_array;
			}elsif($i<0){
				if(defined $cs_cluster_neg[0]){
					die "You can only have one negative coagulation sink cluster.\n";
				}
				@cs_cluster_neg = @temp_array;
			}else{
				if(defined $cs_cluster_pos[0]){
					die "You can only have one positive coagulation sink cluster.\n";
				}
				@cs_cluster_pos = @temp_array;
			}
	
################################################################################
################################################################################
##      2.4 Reading the cluster types                                         ##
################################################################################
################################################################################
		
		}elsif($#columns == $nmol_types-1 || $input_file[$iline] =~ /no evap/i){
		
			# Removing the columns not related to molecule numbers from the lines starting with "no evap"
			while($nmol_types-1<$#columns){
				shift(@columns);
			}
		
			# Checking which column (if any) contains a range of molecule numbers
			for($icol=0;$icol<$nmol_types;$icol++){
				$lfound = 0;
				if($columns[$icol] =~ /(\d+)\-(\d+)/){
					$lfound = 1;
					last;
				}
			}
			if(!$lfound){
#				print "\nIf you only want to specify one cluster by the line\n'$input_file[$iline]',\nyou should use $columns[0]-$columns[0] for the first molecule type. Trying to proceed anyway, but fix your input file to be safe.\n\n";
				$columns[0] = "$columns[0]-$columns[0]";
				$icol = 0;
			}
		
			# Creating cluster labels and recording their compositions
			$columns[$icol] =~ /(\d+)\-(\d+)/;
			for($jclus=$1;$jclus<=$2;$jclus++){
				$max_cluster++;
				$columns[$icol]=$jclus;
				$nmol = 0;
				for($imol=0;$imol<$nmol_types;$imol++){
					$nmol += $columns[$imol];
				}
				if($nmol < 1){
					die "\nYou have a cluster with no molecules in the input file!\n\n";
				}
				push(@clust_comp,[@columns]);
			
				# Recording whether this cluster can evaporate
				if($input_file[$iline] =~ /no evap/i){
					$disable_evap_only[$max_cluster]=1;
				}else{
					$disable_evap_only[$max_cluster]=0;
				}
			
				# these logicals tell if the cluster is negative, positive or neutral (1 is true, 0 is false)
				$lnegative_cluster[$max_cluster]=0;
				$lnegative[$max_cluster]=0;
				$lpositive_cluster[$max_cluster]=0;
				$lpositive[$max_cluster]=0;
				$lneutral_cluster[$max_cluster]=1;
				$lneutral[$max_cluster]=1;
				for($imol=0;$imol<$nmol_types;$imol++){
					if($clust_comp[$max_cluster][$imol] > 0){
						if($charge[$imol] < 0){
							$found_negative =1;
							$lnegative_cluster[$max_cluster]=1;
							$lnegative[$max_cluster]=1;
							$lneutral_cluster[$max_cluster]=0;
							$lneutral[$max_cluster]=0;
							push(@negative_clusters,$max_cluster);
							if($clust_comp[$max_cluster][$imol] > 1){
								die "\nCan't have more than one charged molecule per cluster!\n\n";
							}
						}elsif($charge[$imol] > 0){
							$found_positive =1;
							$lpositive_cluster[$max_cluster]=1;
							$lpositive[$max_cluster]=1;
							$lneutral_cluster[$max_cluster]=0;
							$lneutral[$max_cluster]=0;
							push(@positive_clusters,$max_cluster);
							if($clust_comp[$max_cluster][$imol] > 1){
								die "\nCan't have more than one charged molecule per cluster!\n\n";
							}
						}
					}
				}
				if($lnegative_cluster[$max_cluster] && $lpositive_cluster[$max_cluster]){
					die "\nCan't have both negative and positive molecules in the same cluster!\n\n";
				}
				if($lnegative_cluster[$max_cluster]){
					for($imol=0;$imol<$nmol_types;$imol++){
							$nmol = $clust_comp[$max_cluster][$imol];
							if($n_max_type_neg[$imol] < $nmol){
								$n_max_type_neg[$imol] = $nmol;
							}
#							if($charge[$imol] == 0 && $n_corr_negative_mol[$imol] >= 0){
#								$nmol += $clust_comp[$max_cluster][$n_corr_negative_mol[$imol]];
#							}
#							if($charge[$imol] < 0 && $n_corr_neutral_mol[$imol] >= 0){
#								$nmol -= $clust_comp[$max_cluster][$n_corr_neutral_mol[$imol]];
#								$nmol = max($nmol,0);
#							}
#							if($n_max_type_neg_0[$imol] < $nmol){
#								$n_max_type_neg_0[$imol] = $nmol;
#							}
					}
				}elsif($lpositive_cluster[$max_cluster]){
					for($imol=0;$imol<$nmol_types;$imol++){
							$nmol = $clust_comp[$max_cluster][$imol];
							if($n_max_type_pos[$imol] < $nmol){
								$n_max_type_pos[$imol] = $nmol;
							}
#							if($charge[$imol] == 0 && $n_corr_positive_mol[$imol] >= 0){
#								$nmol = $nmol+$clust_comp[$max_cluster][$n_corr_positive_mol[$imol]];
#							}
#							if($charge[$imol] > 0 && $n_corr_neutral_mol[$imol] >= 0){
#								$nmol -= $clust_comp[$max_cluster][$n_corr_neutral_mol[$imol]];
#								$nmol = max($nmol,0);
#							}
#							if($n_max_type_pos[$imol] < $nmol){
#								$n_max_type_pos[$imol] = $nmol;
#							}
					}
				}else{
					for($imol=0;$imol<$nmol_types;$imol++){
							if($n_max_type[$imol] < $clust_comp[$max_cluster][$imol]){
								$n_max_type[$imol] = $clust_comp[$max_cluster][$imol];
							}
					}
				}
			
				# Make the cluster label
				$label[$max_cluster]=&create_label(\@columns);
				if($l_print_boundary){
					print "Cluster $max_cluster: $label[$max_cluster]\n";
				}
				$comments[$max_cluster]="% Cluster $max_cluster: $label[$max_cluster]";
				$num_from_label{"$label[$max_cluster]"} = $max_cluster;

				# check if this is a monomer
				$lmonomer[$max_cluster]=&check_monomer(\@columns);
				if ($lmonomer[$max_cluster]){
					$nmolecules += 1;
					$molecules[$nmolecules] = $max_cluster;
				}
			
				# get the mass and radius of the cluster
				$clust_mass[$max_cluster][0] = &calculate_mass(\@columns);
				if($l_bulk_density){
					if($lhydrate_average){
						($clust_volume[$max_cluster],$clust_radius[$max_cluster][0]) = &calculate_volume_and_radius(\@columns);
					}else{
						$clust_radius[$max_cluster][0] = &calculate_radius(\@columns);
					}
				}
				#print "$label[$max_cluster]: mass = $clust_mass[$max_cluster][0], radius =  $clust_radius[$max_cluster][0]\n";
			}
		}else{
			print "Cannot understand this line of the input file. Line number: ".($iline+1)."\nData on line: $input_file[$iline]\ncolumns:$#columns\nnmol_types-1:".($nmol_types-1)."\n";
			die;
		}
	}
}
## Done reading the input file

if($lloop && $max_cluster>1){
	die "Too many clusters in the input file! In loop mode, you should only give the composition of the biggest cluster.\n";
}
if($lloop && ($n_nucl_rules>0 || $n_nucl_rules_neg>0 || $n_nucl_rules_pos>0)){
	die "You should not define nucleation rules in loop mode - all outgoing collisions are allowed.\n";
}

# Adding a cluster number for the formed particles if they act as a coag. sink
if($use_coag_to_outgoing){
	if($n_nucl_rules>0){
		if(!defined($cs_cluster[0])){
			die "Define a coagulation sink cluster also for neutrals, or none at all.";
		}
		$max_cluster++;
		$n_flux_out=$max_cluster;
		$n_flux_out_max=$n_flux_out;
		push(@clust_comp,[@cs_cluster]);
		# Make the cluster label
		$cs_cluster_label=&create_label(\@cs_cluster);
		$label[$max_cluster]='cs_cluster';
		if($l_print_boundary){
			print "Cluster $max_cluster: $label[$max_cluster] (=formed neutral particles)\n";
		}
		$comments[$max_cluster]="% Cluster $max_cluster: $label[$max_cluster] (=formed particles)";
		$lnegative_cluster[$max_cluster]=0;
		$lnegative[$max_cluster]=0;
		$lpositive_cluster[$max_cluster]=0;
		$lpositive[$max_cluster]=0;
		$lneutral_cluster[$max_cluster]=1;
		$lneutral[$max_cluster]=1;
		# get the mass and radius of the cluster
		$clust_mass[$max_cluster][0] = &calculate_mass(\@cs_cluster);
		if($l_bulk_density){
			$clust_radius[$max_cluster][0] = &calculate_radius(\@cs_cluster);
		}
	}
	if($n_nucl_rules_neg>0){
		if(!defined($cs_cluster_neg[0])){
			die "Define a coagulation sink cluster also for negatives, or none at all.";
		}
		$max_cluster++;
		$n_flux_out_neg=$max_cluster;
		$n_flux_out_max=$n_flux_out_neg;
		push(@clust_comp,[@cs_cluster_neg]);
		# Make the cluster label
		$cs_cluster_neg_label=&create_label(\@cs_cluster_neg);
		$label[$max_cluster]='cs_cluster_neg';
		if($l_print_boundary){
			print "Cluster $max_cluster: $label[$max_cluster] (=formed negative particles)\n";
		}
		$comments[$max_cluster]="% Cluster $max_cluster: $label[$max_cluster] (=formed negative particles)";
		$lnegative_cluster[$max_cluster]=1;
		$lnegative[$max_cluster]=1;
		$lpositive_cluster[$max_cluster]=0;
		$lpositive[$max_cluster]=0;
		$lneutral_cluster[$max_cluster]=0;
		$lneutral[$max_cluster]=0;
		# get the mass and radius of the cluster
		$clust_mass[$max_cluster][0] = &calculate_mass(\@cs_cluster_neg);
		if($l_bulk_density){
			$clust_radius[$max_cluster][0] = &calculate_radius(\@cs_cluster_neg);
		}
	}
	if($n_nucl_rules_pos>0){
		if(!defined($cs_cluster_pos[0])){
			die "Define a coagulation sink cluster also for positives, or none at all.";
		}
		$max_cluster++;
		$n_flux_out_pos=$max_cluster;
		$n_flux_out_max=$n_flux_out_pos;
		push(@clust_comp,[@cs_cluster_pos]);
		# Make the cluster label
		$cs_cluster_pos_label=&create_label(\@cs_cluster_pos);
		$label[$max_cluster]='cs_cluster_pos';
		if($l_print_boundary){
			print "Cluster $max_cluster: $label[$max_cluster] (=formed positive particles)\n";
		}
		$comments[$max_cluster]="% Cluster $max_cluster: $label[$max_cluster] (=formed positive particles)";
		$lnegative_cluster[$max_cluster]=0;
		$lnegative[$max_cluster]=0;
		$lpositive_cluster[$max_cluster]=1;
		$lpositive[$max_cluster]=1;
		$lneutral_cluster[$max_cluster]=0;
		$lneutral[$max_cluster]=0;
		# get the mass and radius of the cluster
		$clust_mass[$max_cluster][0] = &calculate_mass(\@cs_cluster_pos);
		if($l_bulk_density){
			$clust_radius[$max_cluster][0] = &calculate_radius(\@cs_cluster_pos);
		}
	}
}


for($imol=0;$imol<$nmol_types;$imol++){
	# Array for cluster numbers corresponding to monomers
	$clust_num_of_monomer[$imol] = &get_cluster_number("1$molecule_name[$imol]");
	# If the acid and base strengths were not given, give the same value for all molecules
	if(!(defined $acid_strength[$imol])){
		$acid_strength[$imol] = 0;
	}
	if(!(defined $base_strength[$imol])){
		$base_strength[$imol] = 0;
	}
	if($charge[$imol] == 0){
		push(@neutral_mols,$imol);
		$n_neutral_mols++;
		# See if any acid and/or base strengths are given for neutral molecules
		if($acid_strength[$imol] > 0 || $base_strength[$imol] > 0){
			$l_strength_neutral = 1;
		}
	}
}

################################################################################
################################################################################
##      2.5 Adding molecule types for the proton and removed proton if needed ##
################################################################################
################################################################################

$include_negative_ion_terms = 0;
$include_positive_ion_terms = 0;
$include_ion_terms = 0;

if($found_negative){
	$include_negative_ion_terms = 1;
	$include_ion_terms = 1;
	$ncharges += 1;
}
if($found_positive){
	$include_positive_ion_terms = 1;
	$include_ion_terms = 1;
	$ncharges += 1;
}

if(!$include_ion_terms){
	# if we don't have any ions, no need to include generic charger ions
	$include_generic_ions = 0;
}

if($variable_ion_source && (!$include_negative_ion_terms || !$include_positive_ion_terms)){
	die "\nThe --variable_ion_source option works only when ions are included.\n\n";
}

if($include_generic_ions){
	if($no_generic_neg){
		$include_generic_neg = 0;
	}else{
		$include_generic_neg = 1;
	}
	if($no_generic_pos){
		$include_generic_pos = 0;
	}else{
		$include_generic_pos = 1;
	}
}

# if we have charger ions or several molecule types that can get charged to the same polarity, 
# we need molecule types for the proton and/or removed proton

# first checking the proton ...
if($proton==-1){
	$label_proton = '';
	$lfound = -1;
	for($imol=0;$imol<$nmol_types;$imol++){
		if($charge[$imol] == 1 && $n_corr_neutral_mol[$imol] >= 0){
			$lfound += 1;
			if($label_proton eq ''){
				$label_proton = "$molecule_name[$imol]-1$molecule_name[$n_corr_neutral_mol[$imol]]";
			}else{
				print "Warning: the positive charge might not be able to move from one molecule type to another.\n";
			}
		}
	}
	if($include_generic_pos){
		$lfound = 1;
	}
	if($lfound>=1 && $label_proton eq ''){
		$label_proton = 'P';
		$proton = $nmol_types;
		$nmol_types += 1;
		$molecule_name[$proton] = 'P';
		$mol_num_from_name{'P'}=$proton;
		$charge[$proton] = 1;
		$corr_neutral_mol[$proton] = '';
		$corr_negative_mol[$proton] = '';
		$corr_positive_mol[$proton] = '';
		$n_corr_neutral_mol[$proton] = -1;
		$n_corr_negative_mol[$proton] = -1;
		$n_corr_positive_mol[$proton] = -1;
		$mass[$proton] = 1.*$mass_conv;
		$density[$proton] = '';
		$acid_max += 1;
		$acid_strength[$proton] = $acid_max;
		# Add the new molecule type also in the cluster composition table ...
		for($i=1;$i<=$max_cluster;$i++){
			$clust_comp[$i][$proton] = 0;
		}
		# ... and in the nucleation rules		
		for($i=0;$i<$n_nucl_rules;$i++){
			$nucl_rules[$i][$proton] = 0;
		}
		for($i=0;$i<$n_nucl_rules_neg;$i++){
			$nucl_rules_neg[$i][$proton] = 0;
		}
		for($i=0;$i<$n_nucl_rules_pos;$i++){
			$nucl_rules_pos[$i][$proton] = 0;
		}
	}
}else{
	$label_proton = $molecule_name[$proton];
}

# ... then the missing proton
if($missing_proton==-1){
	$label_missing_proton = '';
	$lfound = -1;
	for($imol=0;$imol<$nmol_types;$imol++){
		if($charge[$imol] == -1 && $n_corr_neutral_mol[$imol] >= 0){
			$lfound += 1;
			if($label_missing_proton eq ''){
				$label_missing_proton = "$molecule_name[$imol]-1$molecule_name[$n_corr_neutral_mol[$imol]]";
			}else{
				print "Warning: the negative charge might not be able to move from one molecule type to another.\n";
			}
		}
	}
	if($include_generic_neg){
		$lfound = 1;
	}
	if($lfound>=1 && $label_missing_proton eq ''){
		$label_missing_proton = 'RP';
		$missing_proton = $nmol_types;
		$nmol_types += 1;
		$molecule_name[$missing_proton] = 'RP';
		$mol_num_from_name{'RP'}=$missing_proton;
		$charge[$missing_proton] = -1;
		$corr_neutral_mol[$missing_proton] = '';
		$corr_negative_mol[$missing_proton] = '';
		$corr_positive_mol[$missing_proton] = '';
		$n_corr_neutral_mol[$missing_proton] = -1;
		$n_corr_negative_mol[$missing_proton] = -1;
		$n_corr_positive_mol[$missing_proton] = -1;
		$mass[$missing_proton] = -1.*$mass_conv;
		$density[$missing_proton] = '';	
		$base_max += 1;
		$base_strength[$missing_proton] = $base_max;
		# Add the new molecule type also in the cluster composition table ...
		for($i=1;$i<=$max_cluster;$i++){
			$clust_comp[$i][$missing_proton] = 0;
		}
		# ... and in the nucleation rules		
		for($i=0;$i<$n_nucl_rules;$i++){
			$nucl_rules[$i][$missing_proton] = 0;
		}
		for($i=0;$i<$n_nucl_rules_neg;$i++){
			$nucl_rules_neg[$i][$missing_proton] = 0;
		}
		for($i=0;$i<$n_nucl_rules_pos;$i++){
			$nucl_rules_pos[$i][$missing_proton] = 0;
		}	
	}
}else{
	$label_missing_proton = $molecule_name[$missing_proton];
}

################################################################################
################################################################################
##      2.6 Determining the system size for the loop option                   ##
################################################################################
################################################################################
if($lloop){

	$max_cluster = 1;
	for($imol=0;$imol<$nmol_types;$imol++){
		if($n_max_type[$imol]>0){
			$max_cluster *= ($n_max_type[$imol]+1); # the "+1" corresponds to zero molecules
		}
	}
	$max_cluster -= 1; # the total number of all molecules can't be zero
	
	# Determine the maximum numbers for fluxes and clusters
	if($l_save_outgoing){
		$max_n_flux = $max_cluster+1;
	}else{
		$max_n_flux = $max_cluster;
	}
	$max_cluster_number = $max_cluster;
	
}else{
################################################################################
################################################################################
##      2.7 Adding cluster numbers for generic ions if they are used          ##
################################################################################
################################################################################

	# $max_cluster is the largest number for a proper cluster (possibly including the formed particles)
	# $max_cluster_number is the largest number for a cluster or generic ion
	$max_cluster_number=$max_cluster;
	$n_generic_neg=-1;
	$n_generic_pos=-1;

	if($include_generic_neg){
		$n_generic_neg=$max_cluster_number+1;
		$lnegative[$n_generic_neg] = 1;
		$lpositive[$n_generic_neg] = 0;
		$lneutral_cluster[$n_generic_neg] = 0;
		$label[$n_generic_neg]=$label_generic_neg;
		$comments[$n_generic_neg]="% Cluster $n_generic_neg: generic negative ion ";
		$max_cluster_number=$n_generic_neg; 
	
		# get the "composition" of the cluster	
		($ref,$comp_ok)=&determine_cluster_composition($label_generic_neg);
		if($comp_ok ne ''){
			die "Couldn't determine the composition of the negative charger ion.\n";
		}else{
			$clust_comp[$n_generic_neg] = [@$ref];
		}
	
		# get the mass and radius of the cluster
		$clust_mass[$max_cluster_number][0] = $mass_nion;
		if($l_bulk_density){
			$clust_radius[$max_cluster_number][0] = ($mass_nion/$dens_nion/4.0*3.0/$pi)**(1.0/3.0);
		}
	}
	if($include_generic_pos){
		$n_generic_pos=$max_cluster_number+1;
		$lnegative[$n_generic_pos] = 0;
		$lpositive[$n_generic_pos] = 1;
		$lneutral_cluster[$n_generic_pos] = 0;
		$label[$n_generic_pos]=$label_generic_pos;
		$comments[$n_generic_pos]="% Cluster $n_generic_pos: generic positive ion ";
		$max_cluster_number=$n_generic_pos;
	
		# get the "composition" of the cluster	
		($ref,$comp_ok)=&determine_cluster_composition($label_generic_pos);
		if($comp_ok ne ''){
			die "Couldn't determine the composition of the positive charger ion.\n";
		}else{
			$clust_comp[$n_generic_pos] = [@$ref];
		}
	
		# get the mass and radius of the cluster
		$clust_mass[$max_cluster_number][0] = $mass_pion;
		if($l_bulk_density){
			$clust_radius[$max_cluster_number][0] = ($mass_pion/$dens_pion/4.0*3.0/$pi)**(1.0/3.0);
		}
	}

################################################################################
################################################################################
##      2.8 Adding cluster numbers for other fluxes                           ##
################################################################################
################################################################################

	$i = 0;
	$i = $i + 1;
	$n_flux_source=$max_cluster_number+$i;
	$i = $i + 1;
	$n_flux_coag=$max_cluster_number+$i;
	$i = $i + 1;
	$n_flux_wall=$max_cluster_number+$i;
	$i = $i + 1;
	$n_flux_dil=$max_cluster_number+$i;
	$i = $i + 1;
    $n_flux_insink=$max_cluster_number+$i;
	$i = $i + 1;
	$n_flux_rec=$max_cluster_number+$i;
	$label[$n_flux_source]="source";
	$label[$n_flux_coag]="coag";
	$label[$n_flux_wall]="wall";
	$label[$n_flux_dil]="dil";
    $label[$n_flux_insink]="insink";
	$label[$n_flux_rec]="rec";
	$comments[$n_flux_source]="% $n_flux_source is for source fluxes";
	$comments[$n_flux_coag]="% $n_flux_coag is for coagulation losses";
	$comments[$n_flux_wall]="% $n_flux_wall is for wall losses";
	$comments[$n_flux_dil]="% $n_flux_dil is for dilution losses";
    $comments[$n_flux_insink]="% $n_flux_insink is for user-defined losses";
	$comments[$n_flux_rec]="% $n_flux_rec is for recombination of positive and negative charger ions with each other";
	if($use_coag_to_outgoing){
		$i = $i + 1;
		$n_coag_on_formed_clusters = $max_cluster_number+$i;
		$label[$n_coag_on_formed_clusters] = "coag2";
		$comments[$n_coag_on_formed_clusters] = "% $n_coag_on_formed_clusters is for coagulation losses on formed clusters";
	}
	if(!defined($n_flux_out)){
		$i = $i + 1;
		$n_flux_out=$max_cluster_number+$i;
		$n_flux_out_max=$n_flux_out;
		$label[$n_flux_out]="out_neu";
		$comments[$n_flux_out]="% $n_flux_out is for collisions that lead succesfully out of the system as neutrals";
		$lneutral[$n_flux_out] = 1;
		$lnegative[$n_flux_out] = 0;
		$lpositive[$n_flux_out] = 0;
	}
	if($include_negative_ion_terms && !defined($n_flux_out_neg)){
		$i = $i + 1;
		$n_flux_out_neg=$max_cluster_number+$i;
		$n_flux_out_max=$n_flux_out_neg;
		$label[$n_flux_out_neg]="out_neg";
		$comments[$n_flux_out_neg]="% $n_flux_out_neg is for collisions that lead succesfully out of the system as negatives";
		$lneutral[$n_flux_out_neg] = 0;
		$lnegative[$n_flux_out_neg] = 1;
		$lpositive[$n_flux_out_neg] = 0;
	}elsif(!$include_negative_ion_terms){
		$n_flux_out_neg=-1
	}
	if($include_positive_ion_terms && !defined($n_flux_out_pos)){
		$i = $i + 1;
		$n_flux_out_pos=$max_cluster_number+$i;
		$n_flux_out_max=$n_flux_out_pos;
		$label[$n_flux_out_pos]="out_pos";
		$comments[$n_flux_out_pos]="% $n_flux_out_pos is for collisions that lead succesfully out of the system as positives";
		$lneutral[$n_flux_out_pos] = 0;
		$lnegative[$n_flux_out_pos] = 0;
		$lpositive[$n_flux_out_pos] = 1;
	}elsif(!$include_positive_ion_terms){
		$n_flux_out_pos=-1
	}
	if($l_reac_in_clus){
		$i = $i + 1;
		$n_react_in_clust = $max_cluster_number+$i;
		$label[$n_react_in_clust] = "react";
		$comments[$n_react_in_clust] = "% $n_react_in_clust is for chemical reactions inside clusters";
	}

	if(!$keep_boundary_clusters){
		$i = $i + 1;
		$n_flux_bound=$max_cluster_number+$i;
		$label[$n_flux_bound]="bound";
		$comments[$n_flux_bound]="% $n_flux_bound is for collisions that lead out of the system, but the resulting cluster is brought back";
	}

	# This is the size of the flux matrix, used to loop over all fluxes EXCEPT the explicit boundary clusters, if we're keeping them
	$max_n_flux=$max_cluster_number+$i;
    # Ensure that all labels are included in num_from_label
    for($iclus=1;$iclus<=$max_n_flux;$iclus++){
        if(! exists $num_from_label{"$label[$iclus]"}){
            $num_from_label{"$label[$iclus]"} = $iclus;
        }
    }
    
	# Size of the flux matrix including the boundary clusters
	# This will be updated when we find out the boundary clusters while looping through the collisions;
    # also num_from_label will be updated accordingly
	$max_n_flux_inc_boundary_clusters=$max_n_flux;
	@label_inc_boundary_clusters=@label;

	if($l_print_boundary){
		for($i=$max_cluster+1;$i<=$max_cluster_number;$i++){
			$str_temp = $comments[$i];
			$str_temp =~ s/% //;
			print "$str_temp\n";
		}
		for($i=$max_cluster_number+1;$i<=$max_n_flux;$i++){
			$str_temp = $comments[$i];
			$str_temp =~ s/%/Flux/;
			print "$str_temp\n";
		}
	}
    
    # Labels for outgrown products; the 0th element is empty in order to number them from 1 similarly to the simulated clusters
    # This will be updated when we find out the outgrown clusters while looping through the collisions
    @label_out = ('');
    @clust_comp_out = ([0]);
    $n_comp_out = 0;
    
}

# Number of equations to allocate the Fortran index and coefficient arrays
$size_ind_coef = $max_n_flux;

# Numbers of optional elements in addition to the cluster and flux names
$n_coag_per_clust = 0;
$n_out_clust = 0;
@range_coag_per_clust = (-1, -1);
@range_out_clust = (-1, -1);

if($l_save_outgoing){
    # If also individual outgrowing clusters are saved, their number will be added after it has been determined from the equations
	$size_C_out = $max_n_flux;
    if($l_save_coag_per_clust){
        # Coagulation per cluster
        # Note: generic ions are included here; they can be excluded by using $max_cluster instead of $max_cluster_number, but
        # in this case also the coagulation arrays in all Fortran routines that apply ACDC must be allocated accordingly
        $n_coag_per_clust = $max_cluster_number;
        $size_C_out += $n_coag_per_clust;
    }
}else{
	$size_C_out = $max_cluster_number;
}

################################################################################
################################################################################
##      2.9 Checking which molecule types are used in the system              ##
################################################################################
################################################################################

$nmol_types_used = 0;
@mol_types_used = ();
@mol_names_used = ();
# Determine the numbers of used molecule types and their indices, as well as monomer indices
if($lloop){
	@nmol_ranges_array = ();
	$nmol_ranges_list = '';
	$nmol_comp_list = '';
	$nmol_ranges_ind = '';
	$nmol_ranges_ij_ind = '';
	for($imol=0;$imol<$nmol_types;$imol++){
		if($n_max_type[$imol]>0){
			$nmol_types_used += 1;
			$mol_types_used[$nmol_types_used] = $imol;
			$mol_names_used[$nmol_types_used] = $molecule_name[$imol];
			$nmol_ranges_array[$nmol_types_used] = $n_max_type[$imol];
			$nmol_ranges_list .= "$n_max_type[$imol],";
			$nmol_comp_list .= "0:".(2*$n_max_type[$imol]).",";
			$nmol_ranges_ind .= "i".($nmol_types_used).", ";
			$nmol_ranges_ij_ind .= "ij_ind(".($nmol_types_used)."),";
		}
	}
	$nmol_ranges_list =~ s/,$//;
	$nmol_comp_list =~ s/,$//;
	$nmol_ranges_ind =~ s/, $//;
	$nmol_ranges_ij_ind =~ s/,$//;
	if($lloop_restrict && $nmol_types_used == 1){
		die "Found only one molecule type in the input file; options --restrict and --boundary are for several molecule types\n";
	}
	if($l_j_in && $nmol_types_used > 1){
		die "Found $nmol_types_used molecule types in the input file; option --j_in only works with one\n";
	}
	
	$nmolecules = $nmol_types_used; # loop mode: monomers = molecules, as there are no charges included for now
	if($nmol_types_used==1){
		$monomer_indices = "1";
	}else{
		$monomer_indices = "n_monomers";
	}
	
	# Determine the index label for the outgoing flux, or molecule numbers for the cs cluster
	if($lloop_cs){
		if($nmol_types_used==1){
			$n_flux_out = 'n_cs';
		}elsif(defined $cs_cluster[0]){
			for($imol=0;$imol<$nmol_types;$imol++){
				if($cs_cluster[$imol]>$n_max_type[$imol]){
					die "In the loop mode, the coagulation sink cluster must be inside the system\n";
				}
			}
			$nmol_cs_list = join(',',@cs_cluster[@mol_types_used[1..$nmol_types_used]]);
		}else{
			# If no cs cluster is given, use the cluster with the largest number of molecules
			$nmol_cs_list = $nmol_ranges_list;
		}
	}else{
		$n_flux_out = "$nclust_included+1";
	}
	
}else{
	for($imol=0;$imol<$nmol_types;$imol++){
		if($n_max_type[$imol]>0 || $n_max_type_neg[$imol]>0 || $n_max_type_pos[$imol]>0){
			$nmol_types_used += 1;
			$mol_types_used[$nmol_types_used] = $imol;
			$mol_names_used[$nmol_types_used] = $molecule_name[$imol];
		}
	}
	$string2 = '';
	for($imol=1;$imol <= $nmolecules;$imol++){
		$string2 .= "$molecules[$imol], ";
	}
	$string2 =~ s/, $//;
	$monomer_indices = $string2;
}
if(!$lsilent){
    print "\nMolecule types included in the system:\n";
    for($imol=1;$imol<=$nmol_types_used;$imol++){
        print "name $mol_names_used[$imol], charge $charge[$mol_types_used[$imol]]\n";
    }
    print "\n";
}

################################################################################
################################################################################
##   3. Dealing with forbidden reactions                                      ##
##      and reactions with nonstandard products                               ##
################################################################################
################################################################################

# If some cluster-cluster collisions are allowed, determining the corresponding cluster numbers
if($#nonmonomer_collisions_only>=0){
	@temp_array = @nonmonomer_collisions_only;
	@nonmonomer_collisions_only = ();
	for($i=0;$i<=$#temp_array;$i++){
		# Checking if the cluster definition contains a range of molecule numbers
		if($temp_array[$i] =~ /(\d+)\-(\d+)/){
			@temp_array_2 = split("$1-$2",$temp_array[$i]);
			for($j=$1;$j<=$2;$j++){
				$iclus=&get_cluster_number("$temp_array_2[0]$j$temp_array_2[1]");
				if($iclus eq ''){
					print "\nCould not find cluster $temp_array_2[0]$j$temp_array_2[1] in the system -> not using it to define allowed cluster-cluster collisions.\n";
				}else{
					push(@nonmonomer_collisions_only,$iclus);
				}
			}
		}else{
			$iclus=&get_cluster_number($temp_array[$i]);
			if($iclus eq ''){
				print "\nCould not find cluster $temp_array[$i] in the system -> not using it to define allowed cluster-cluster collisions.\n";
			}else{
				push(@nonmonomer_collisions_only,$iclus);
			}
		}
	}
}

# Now reading the file for reactions with nonstandard products
if($nonstandard_reaction_file_name eq ''){
	$l_nonstandard_allowed = 0;
}else{
	$l_nonstandard_allowed = 1;

	# array for collisions that are in principle valid but are not used
	for($iclus=1;$iclus<=$max_cluster;$iclus++){
		for($jclus=1;$jclus<=$max_cluster;$jclus++){
			$l_coll_not_used[$iclus][$jclus] = 0;
		}
	}
	# array for other non-standard reactions
	for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
		for($jclus=1;$jclus<=$max_cluster_number;$jclus++){
			$nonstandard_reactions[$iclus][$jclus][0] = ();
		}
	}
	
	open(NONACC, "<$nonstandard_reaction_file_name") || die "\nCould not open energy non-accommodation file $nonstandard_reaction_file_name\n\n";
	chomp(@nonstandard_reaction_data=<NONACC>);
	close(NONACC);
	$number_of_lines=$#nonstandard_reaction_data+1;
	for($iline=0;$iline<$number_of_lines;$iline++){
		next if (($nonstandard_reaction_data[$iline] =~ /^\#/) || ($nonstandard_reaction_data[$iline] =~ /^\s*$/));
		@columns=split(' ',$nonstandard_reaction_data[$iline]);
		# the line must have an even number of entries (colliding molecules + products preceded by a coefficient)
		die "\nLines in nonaccommodation file $nonstandard_reaction_file_name have to contain colliding molecules + products preceded by coefficients.\n\n" if ($#columns % 2 == 0);
		#first two entries on the line should be the colliding molecules
		$iclus=&get_cluster_number($columns[0]);
		if($iclus eq ''){
			print "\nCould not find cluster $columns[0] in the system -> not using non-standard reaction '$nonstandard_reaction_data[$iline]'.\n";
			next;
		}
		$lmonomer1=$lmonomer[$iclus];
		$temp_label=$columns[1];
		# Now check if this line is for forbidding cluster-cluster collisions
		if(!$lmonomer1 && $#columns==1 && ($temp_label =~ /clusters/i)){
			for($jclus=1;$jclus<=$max_cluster;$jclus++){
				$lmonomer2=$lmonomer[$jclus];
				if(!$lmonomer2 && $jclus!=$n_flux_out && $jclus!=$n_flux_out_neg && $jclus!=$n_flux_out_pos){
					$l_coll_not_used[$iclus][$jclus] = 1;
					$l_coll_not_used[$jclus][$iclus] = 1;
				}
			}
			next;
		}
		$jclus=&get_cluster_number($temp_label);
		if($jclus eq ''){
			print "\nCould not find cluster $temp_label in the system -> not using non-standard reaction '$nonstandard_reaction_data[$iline]'.\n";
			next;
		}
		$lmonomer2=$lmonomer[$jclus];
		
		# If the line only contains the colliding clusters, this is interpreted as meaning that the collision is forbidden.
		if($#columns==1){
			$columns[2] = 1;
			$columns[3] = $columns[0];
			$columns[4] = 1;
			$columns[5] = $columns[1];
		}
		
		# if this line defines a forbidden collision, no point in printing equations of the type x + y -> x + y
		if($disable_useless_collisions){
			if($#columns==1 || (($#columns==5)&&(&compare_clusters($columns[3],$label[$iclus]) || &compare_clusters($columns[5],$label[$iclus]))&&($columns[2]==1.00)) || (($#columns==3)&&($lmonomer1)&&($columns[2]==2.00))){
				if(($columns[3] eq $label[$iclus]) || ($columns[3] eq $label[$jclus])){
					$l_coll_not_used[$iclus][$jclus] = 1;
					$l_coll_not_used[$jclus][$iclus] = 1;
				}
			}
		}
		# going through the rest of the line
		for($icol=2;$icol<$#columns;$icol+=2){
			# every other entry should be a positive number (coefficient for the reaction product)
			die "\n$columns[$icol] on line $iline in file $nonstandard_reaction_file_name should be a positive nuber\n\n" if (!&is_pos_number($columns[$icol]));
			if($lfortran && $columns[$icol] =~ m/\./){
				die "Non-standard reactions with non-integer coefficients don't work in the Fortran version.\n";
			}
			$coef_temp = sprintf("%.2f",$columns[$icol]);
			if($lfortran){
				$coef_temp =~ s/e/d/;
			}
			push(@{ $nonstandard_reactions[$iclus][$jclus] },$columns[$icol]);
			if($iclus != $jclus){
				push(@{ $nonstandard_reactions[$jclus][$iclus] },$columns[$icol]);
			}
			# the next entry should be the corresponding reaction product
			$temp_label=$columns[$icol+1];
			if($temp_label =~ /^out_neu$/i || $temp_label =~ /^out$/i){
				$kclus = $n_flux_out;
				$lfound = 1;
			}elsif($temp_label =~ /^out_neg$/i){
				$kclus = $n_flux_out_neg;
				$lfound = 1;
			}elsif($temp_label =~ /^out_pos$/i){
				$kclus = $n_flux_out_pos;
				$lfound = 1;
			}else{
				$kclus=&get_cluster_number($temp_label);
			}
			die "\nReaction product $temp_label on line $iline in file $nonstandard_reaction_file_name is not a valid cluster\n\n" if ($kclus eq '');
			push(@{ $nonstandard_reactions[$iclus][$jclus] },$kclus);
			if($iclus != $jclus){
				push(@{ $nonstandard_reactions[$jclus][$iclus] },$kclus);
			}
		}
	}
}

################################################################################
################################################################################
##   4. Charge balance for generic positive or negative ions                  ##
################################################################################
################################################################################

if($include_generic_neg && $include_generic_pos){
	$generic_positive_ions = '';
	$generic_negative_ions = '';
	$generic_positive_ions_corr = '';
	$generic_negative_ions_corr = '';
	
	if($l_charge_balance!=0){
		
		# Make strings for printing out the arrays of indices for negative and positive clusters
		if($include_negative_ion_terms){
			if($negative_clusters[$#negative_clusters]-$negative_clusters[0]==$#negative_clusters){
				$string1 = "$negative_clusters[0]:$negative_clusters[$#negative_clusters]";
			}else{
				$string1 = $negative_clusters[0];
				for($iclus=1;$iclus<=$#negative_clusters;$iclus++){
					# Making sure the line won't be too long for the fortran compiler
					if($lfortran && $iclus%20==0){
						$string1 = "$string1, &\n\t\t\t\t\t\t&$negative_clusters[$iclus]";
					}else{
						$string1 = "$string1, $negative_clusters[$iclus]";
					}
				}
				if($lfortran){
					$string1 = "(/$string1/)";
				}
			}
		}
	
		if($include_positive_ion_terms){
			if($positive_clusters[$#positive_clusters]-$positive_clusters[0]==$#positive_clusters){
				$string2 = "$positive_clusters[0]:$positive_clusters[$#positive_clusters]";
			}else{
				$string2 = $positive_clusters[0];
				for($iclus=1;$iclus<=$#positive_clusters;$iclus++){
					# Making sure the line won't be too long for the fortran compiler
					if($lfortran && $iclus%20==0){
						$string2 = "$string2, &\n\t\t\t\t\t\t&$positive_clusters[$iclus]";
					}else{
						$string2 = "$string2, $positive_clusters[$iclus]";
					}
				}
			}
		}
	
		# First the case where we have just negative clusters
		if($include_negative_ion_terms && !$include_positive_ion_terms){

			if($l_charge_balance>0){
				$generic_negative_ions = '';
				$generic_positive_ions = "c($n_generic_neg)+sum(c($string1))";
				if(defined($cs_cluster_neg[0])){
					$generic_positive_ions .= "+c($n_flux_out_neg)";
				}
			}elsif($l_charge_balance<0){
				die "\nNo point in balancing generic negative ions with positive clusters, if there are no positive clusters!\n\n";
			}

		# Then the same in the case that we have just positive clusters
		}elsif(!$include_negative_ion_terms && $include_positive_ion_terms){

			if($l_charge_balance<0){
				$generic_positive_ions = '';
				$generic_negative_ions = "c($n_generic_pos)+sum(c($string2))";
				if(defined($cs_cluster_pos[0])){
					$generic_negative_ions .= "+c($n_flux_out_pos)";
				}
			}elsif($l_charge_balance>0){
				die "\nNo point in balancing generic positive ions with negative clusters, if there are no negative clusters!\n\n";
			}

		# If we have them both
		}elsif($include_negative_ion_terms && $include_positive_ion_terms){

			# This time we want the difference between positive and negative clusters, not including the chargers
			# The concentrations of charger ions of both signs will be set in the Matlab or Fortran equation files
			if($l_charge_balance>0){
				# Sum of negative clusters minus the sum of positive clusters
				if($lfortran && index($string1,',')>=0 && index($string2,',')>=0){
					# Making sure the line won't be too long for the fortran compiler
					$generic_positive_ions_corr = "sum(c($string1))&\n\t\t\t\t\t\t&-sum(c($string2))";
				}else{
					$generic_positive_ions_corr = "sum(c($string1))-sum(c($string2))";
				}
				if(defined($cs_cluster_neg[0])){
					$generic_positive_ions_corr .= "+c($n_flux_out_neg)";
				}
				if(defined($cs_cluster_pos[0])){
					$generic_positive_ions_corr .= "-c($n_flux_out_pos)";
				}
			}elsif($l_charge_balance<0){
				# Sum of positive clusters minus the sum of negative clusters
				if($lfortran && index($string1,',')>=0 && index($string2,',')>=0){
					# Making sure the line won't be too long for the Fortran compiler
					$generic_negative_ions_corr = "sum(c($string2))&\n\t\t\t\t\t\t&-sum(c($string1))";
				}else{
					$generic_negative_ions_corr = "sum(c($string2))-sum(c($string1))";
				}
				if(defined($cs_cluster_pos[0])){
					$generic_negative_ions_corr .= "+c($n_flux_out_pos)";
				}
				if(defined($cs_cluster_neg[0])){
					$generic_negative_ions_corr .= "-c($n_flux_out_neg)";
				}
			}
		}
	}
}

################################################################################
################################################################################
##   5. Reading the Delta G file                                              ##
################################################################################
################################################################################

### Read the DeltaG file for the evaporation coefficients, and find out which clusters
### have hydrates if we're using the hydrate distributions

# Keep track whether there are missing or multiply defined energies, and if so, stop after going through all clusters.
$stopping=0;

if($lhydrate_average){
	# Logical that tells if the cluster has hydrates
	for($iclus=1;$iclus <= $max_n_flux;$iclus++){
		$lhas_hydr[$iclus] = 0;
	}
}

# Energies are needed for evaporations and hydrate distributions, but not necessarily for evaporation rate mcmc.
$evap_comment = '%Note: no energy file was given/read';
if((!$disable_evap || $lhydrate_average) && !($l_evap_factor_mcmc && !$free_energy_file_name) && !$lloop){
	
	if(!$free_energy_file_name){
		die "\nYou didn't give cluster energies!\n\n";
	}
	# read in the energy values, in kcal/mol
	open(GFILE, "<$free_energy_file_name") || die "\nCould not open the delta G file $free_energy_file_name\n\n";
	chomp(@evap_data=<GFILE>);
	close(GFILE);
	$number_of_lines=$#evap_data+1;
	# first line has the pressure in Pa
	if(&is_pos_number($evap_data[0])){
		$pressure=$evap_data[0];
	}else{
		die "\nFirst line of $free_energy_file_name has to be the reference pressure, in Pa.\n\n";
	}
	
################################################################################
################################################################################
##      5.1 Reading Delta G (or H and S) for each cluster and possibly hydrates#
################################################################################
################################################################################

	if ($l_change_temperature){
		if($lfortran){
			$evap_comment = "\t!  Converting thermodynamics data from temperature $temperature_inp K to $temperature K.\n";
		}else{
			$evap_comment = "% Converting thermodynamics data from temperature $temperature_inp K to $temperature K.\n";
		}
	}else{
		$evap_comment = '';
	}
	$temp_val=$pressure/$boltz/$temperature;

	# Going through the clusters in the energy file
	for($iline=2;$iline<$number_of_lines;$iline++){
		next if ($evap_data[$iline] =~ /^\#/);
		next if ($evap_data[$iline] =~ /^\s*$/);
		$evap_data[$iline] =~ s/^\s*//;
		@columns=split(/\b\s+/,$evap_data[$iline]);
#		# if there's white space on the line before the cluster name, remove the corresponding empty column
#		if($columns[0] eq ''){
#			shift(@columns);
#		}
		if ($#columns != 1 && $#columns != 2){
			die "Error on line " . ($iline+1) . " of the energy file: each line must have a cluster name, one or two numbers (G or H and S, respectively) and nothing else.\n";
		}

		$temp_label=$columns[0];
		
		# Checking if we have the cluster (or the corresponding dry one 
		# if we are using hydrates) in the system
		($iclus,$nwaters)=&get_corresponding_dry($temp_label);

		# Save the energy value if we have the cluster (or its dry counterpart) in the system
		if($iclus ne ''){
			# Each cluster must appear only once in the energy file, so the energy should not be defined yet
			if(exists $delta_g_hydr[$iclus][$nwaters]){
				$stopping = 1;
				print "Energy of cluster $temp_label is multiply defined in the energy file $free_energy_file_name.\n";
			}
			# If there are two values, they should be the S and H values
			if($#columns == 2){
				if($variable_temp){
					if($lfortran){
						if($columns[1] =~ m/\./){
							$temp_val = "($columns[1]d0/temperature";
						}else{
							$temp_val = "($columns[1].d0/temperature";
						}
						if($columns[2] =~ m/\./){
							$temp_val = "$temp_val-($columns[2]d0)/1.d3)";
						}else{
							$temp_val = "$temp_val-($columns[2].d0)/1.d3)";
						}
					}else{
						$temp_val = "($columns[1]/temperature-($columns[2])/1000.0)";
					}
				}else{
					$temp_val = $columns[1]-$temperature*$columns[2]/1000.0; # H (and G) in kcal/mol,S in cal/mol/K
					# convert to J from kcal/mol
					$temp_val = $temp_val*$kcal_per_mol_to_J;
				}

			# If there is just one value, it should be the deltaG value in kcal/mol
			}else{
				if($variable_temp){
					die "\nThe option --variable_temp can only be used with H and S values!\n\n";
				}elsif($l_change_temperature){
					die "\nEnergies can only be converted to a different temperature using H and S values!\n\n";
				}
				$temp_val = $columns[1];
				# convert to J from kcal/mol
				$temp_val = $temp_val*$kcal_per_mol_to_J;
			}
			if($nwaters==0){
				$delta_g[$iclus] = $temp_val;
				$delta_g_hydr[$iclus][0] = $temp_val;
			}else{
				$delta_g_hydr[$iclus][$nwaters] = $temp_val;
				$lhas_hydr[$iclus]=1;
				$clust_mass[$iclus][$nwaters] = $clust_mass[$iclus][0]+$nwaters*$mass_water;
				if($l_bulk_density){
					$volume = $clust_volume[$iclus]+$nwaters*$volume_water;
#print "$clust_volume[$iclus]+$nwaters*$volume_water=".($clust_volume[$iclus]+$nwaters*$volume_water)."\n";
					$clust_radius[$iclus][$nwaters] = ($volume/4.0*3.0/$pi)**(1.0/3.0);
#print "$temp_label: mass = $clust_mass[$iclus][$nwaters], radius =  $clust_radius[$iclus][$nwaters]\n";
				}
			}
		}
	}
	# Checking that all energies were given and setting undefined monomer energies to zero
    $string1 = '';
	for($iclus=1;$iclus<=$max_cluster;$iclus++){
        $l_no_delta_g_data[$iclus]=0;
		next if($iclus==$n_flux_out || $iclus==$n_flux_out_neg || $iclus==$n_flux_out_pos);
		if(!(exists $delta_g[$iclus])){
			if($lmonomer[$iclus]){
				if($variable_temp){
					if($lfortran){
						$delta_g[$iclus]='0.d0';
					}else{
						$delta_g[$iclus]='0';
					}
				}else{
					$delta_g[$iclus]=0.0;
					$delta_g_hydr[$iclus][0]=$delta_g[$iclus];
				}
            }elsif($lhydrate_average){
                if($lhas_hydr[$iclus]==0){
                    # Evaporation rate might still be given in an input file, but flag the cluster until the file is read
                    $l_no_delta_g_data[$iclus]=1;
                }
            }else{
                $l_no_delta_g_data[$iclus]=1;
            }
            if($l_no_delta_g_data[$iclus]){
                $string1 .= "Missing energy data for cluster $label[$iclus]";
                if($lhydrate_average){
                    $string1 .= " and its hydrates";
                }
                $string1 .= " in the energy file $free_energy_file_name.\n";
                if($evaporation_coef_file_name eq '' && $disable_evap_only[$iclus]==0){
                    $stopping = 1;
                }
            }
		}
	}
}

if($stopping){
    print $string1;
    die;
}

################################################################################
################################################################################
##      5.2 Calculating hydrate distributions                                 ##
################################################################################
################################################################################

for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
	# Initializing the distribution to the dry cluster for all clusters, also when hydrates are not used
	$distr[$iclus]=[(1)];
	if($lhydrate_average){
		# See if we have the hydrates of this cluster
		$hydrates_str[$iclus]='';
		if($lhas_hydr[$iclus]==1){
			@delta_g_temp = @{$delta_g_hydr[$iclus]};
			
			# Unnormalized hydrate distribution
			$sum=0.0;
			@distr_temp=();
			for($ihydr=0;$ihydr<=$#delta_g_temp;$ihydr++){
				if(defined $delta_g_temp[$ihydr]){
					if($ihydr>0){
						$hydrates_str[$iclus]="$hydrates_str[$iclus]+ $label[$iclus]$ihydr$name_water\t";
					}
					$distr_temp[$ihydr] = ($pw/$pressure)**$ihydr*exp(-$delta_g_temp[$ihydr]/$boltz/$temperature);
					$sum += $distr_temp[$ihydr];
                    #print "$label[$iclus]: hydrate with $ihydr waters included\n";
				}else{
					print "Note: Energy for the hydrate of $label[$iclus] with $ihydr waters is not given, although the cluster has hydrates with more than $ihydr waters.\n";
				}
			}
			# Normalizing the hydrate distribution
			$sum2=0.0;
			for($ihydr=0;$ihydr<=$#distr_temp;$ihydr++){
				if(defined $distr_temp[$ihydr]){
					$distr_temp[$ihydr] /= $sum;
					$sum2 += $distr_temp[$ihydr];
				}
			}
			
			# If the sum of the normalized distribution is not one, don't use the hydrates for this cluster
			if($sum2 > 0.99){
				$distr[$iclus]=[@distr_temp];
			}else{
				print "Found hydrates for $label[$iclus], but the sum of the normalized distribution is $sum2\n";
				print "\t--> Not using the hydrate distribution for $label[$iclus]\n";
			}			
		}
	}	
}

################################################################################
################################################################################
##   6. Making the equations                                                  ##
################################################################################
################################################################################

if(!$lloop){

	# Arrays for indices of collision, evaporation and cluster reaction rates
	for($iclus=1;$iclus <= $max_n_flux;$iclus++){
		$ind_quad_loss[$iclus][0] = 0;
		$ind_quad_form[$iclus][0] = 0;
		$ind_quad_loss_extra[$iclus][0] = 0;
		$ind_quad_form_extra[$iclus][0] = 0;
		$ind_lin_loss[$iclus][0] = 0;
		$ind_lin_form[$iclus][0] = 0;
		$ind_reac_loss[$iclus][0] = 0;
		$ind_reac_form[$iclus][0] = 0;
	}

	# Keep track whether there are missing collision products, and if so, stop at the end of the loops.
	$stopping = 0;

################################################################################
################################################################################
##      6.1 Looping over the clusters and going through all possible collisions#
################################################################################
################################################################################

	EQUATION: for($iclus=1;$iclus<=$max_cluster_number;$iclus++){

		$iclus_label=$label[$iclus];

########################################################################
# Collisions that remove this cluster and evaporations that create it
########################################################################

		for($jclus=$iclus;$jclus<=$max_cluster_number;$jclus++){
			$jclus_label=$label[$jclus];

			# First find out if the collision and evaporation can happen
			$lout=0;
			$l_nonstand=0;
			$l_coag=0;
			%nmonomers = ();
			$coll_coef_temp='';
			$evap_coef_temp='';
			$str_temp = '';
		
			# If the collision is forbidden, forget about it.
			if($l_nonstandard_allowed && $l_coll_not_used[$iclus][$jclus]){
				$valid_coll=0;
				$valid_evap=0;
				if($l_print_boundary){
					print "Not using collision $iclus_label + $jclus_label\n";
				}
				
			# Next option: do we have some special rule for this collision?
			}elsif($l_nonstandard_allowed && $#{ $nonstandard_reactions[$iclus][$jclus] }>0){
				$valid_coll = 1;
				$valid_evap = 0;
				$l_nonstand = 1;
			
			# Next option: these are the generic ions and nothing is formed from their recombination
			}elsif(($iclus==$n_generic_neg && $jclus==$n_generic_pos) || ($iclus==$n_generic_pos && $jclus==$n_generic_neg)){
				$valid_coll = 1;
				$valid_evap = 0;
				$kclus = $n_flux_rec;
			
			# Next option: one or both of the clusters correspond to the pool of formed clusters
			}elsif($jclus==$n_flux_out || $jclus==$n_flux_out_neg || $jclus==$n_flux_out_pos){
				if(($lnegative[$iclus] && $lnegative[$jclus]) || ($lpositive[$iclus] && $lpositive[$jclus])){
					$valid_coll = 0;
					next;
				}else{
					$valid_coll = 1;
					$valid_evap = 0;
					$kclus = $n_coag_on_formed_clusters;
					if($l_print_boundary){
						if($iclus==$n_flux_out || $iclus==$n_flux_out_neg || $iclus==$n_flux_out_pos){
							print "Self coagulation of formed particles: $label[$iclus] + $label[$jclus] -> ";
						}else{
							print "Coagulation on formed particles: $label[$iclus] + $label[$jclus] -> ";
						}
					}
					if($lnegative[$iclus]+$lnegative[$jclus]-$lpositive[$iclus]-$lpositive[$jclus]==0){
						if($l_print_boundary){
							print "cs_cluster\n";
						}
						$l_coag = 1;
					}elsif($lnegative[$iclus]+$lnegative[$jclus]-$lpositive[$iclus]-$lpositive[$jclus]>0){
						if($l_print_boundary){
							print "cs_cluster_neg\n";
						}
						$l_coag = 2;
					}else{
						if($l_print_boundary){
							print "cs_cluster_pos\n";
						}
						$l_coag = 3;
					}
				}
			# Otherwise just collide the clusters and see what we get:
			}else{
				($combined,$valid_coll,$valid_evap,$valid) = &combine_labels($iclus,$jclus);
			
				# If the collision is not possible (e.g. two negative ions), go on to the next one
				if(!$valid_coll){
					next;
				}
			
				if($combined eq ''){
					die "\nCan't figure out what comes from $label[$iclus] + $label[$jclus]\n\n";
				}
			
				# If not, does it satisfy the nucleation criteria or should it be brought back to the system?
				if($valid_coll && !$valid){
					$str_temp = $combined;
					($combined,$lout,%nmonomers)=&check_boundary($combined);
					if($combined eq ''){
						print "Problem with: $label[$iclus] + $label[$jclus] -> $str_temp -> ?\n\n";
						$stopping = 1;
						next;
					}
					$valid_evap=0;
					# Skip the collision, if it doesn't lead out of the system and fancier boundary conditions are disabled
					if($disable_boundary && $lout==0){
						$valid_coll=0;
					}
					# Probably no need to keep this collision, if the products are the same as the reactants
					if($disable_useless_collisions){
						$lmonomer1=$lmonomer[$iclus];
						$lmonomer2=$lmonomer[$jclus];
						if(($lmonomer1 && &compare_clusters($jclus_label,$combined)) ||($lmonomer2 && &compare_clusters($iclus_label,$combined))){
							$valid_coll=0;
							if($l_print_boundary){
								print "Not using boundary collision $iclus_label + $jclus_label -> $iclus_label + $jclus_label\n";
							}
						}
					}
					if($lout>0){
						if($lout==1){
							$temp_val = '_neu';
							$kclus = $n_flux_out;
						}elsif($lout==2){
							$temp_val = '_neg';
							$kclus = $n_flux_out_neg;
						}else{
							$temp_val = '_pos';
							$kclus = $n_flux_out_pos;
						}
                        
                        # See if this outgrowing cluster is already listed
                        # If not, create a new element
                        if(!($str_temp ~~ @label_out)){
                            push(@label_out,$str_temp);
                            ($string1,$string2) = &determine_cluster_composition($str_temp);
                            @temp_array=@$string1;
                            push(@clust_comp_out,[@temp_array]);
                            $n_comp_out += 1;
                        }
                        $i = first { $label_out[$_] eq $str_temp } 0..$#label_out;
                        $ind_out_clust[$iclus][$jclus] = $i;
                        $ind_out_clust[$jclus][$iclus] = $i;
                        
						if($l_print_boundary){
							print "Growing succesfully out: $iclus_label + $jclus_label -> $str_temp -> out$temp_val";
							if($use_coag_to_outgoing){
								print " -> cs_cluster$temp_val\n";
							}else{
								print "\n";
							}
						}
					}elsif($valid_coll && $l_print_boundary){
						print "Brought back to boundary: $iclus_label + $jclus_label -> $str_temp -> $combined";
						for($imol=0;$imol<$nmol_types;$imol++){
							if($nmonomers{$molecule_name[$imol]}>0){
								print " + $nmonomers{$molecule_name[$imol]} $molecule_name[$imol]";
							}
						}
						print "\n";
					}
				}

				# Find the number of the (main) collision product
				if($lout==0){
					$kclus=&get_cluster_number($combined);
					if($kclus eq ''){
						die "Can't find cluster number for $label[$iclus] + $label[$jclus] -> $combined\n";
					}
				}
			}

################################################################################
################################################################################
##      6.2 Save the collision term if the collision can happen               ##
################################################################################
################################################################################
		
			if($valid_coll){
		
				# Collision coefficient for two different clusters ...
				if($iclus != $jclus){
					$coll_coef_temp="K($iclus,$jclus)";
				# ... and for two identical clusters.
				}else{
					if($lfortran){
						$coll_coef_temp="0.5d0*K($iclus,$jclus)";
					}else{
						$coll_coef_temp="0.5*K($iclus,$jclus)";
					}
				}
			
				# Keep track of the number of collision processes (needed for mcmc)
				$ncoef_coll += 1;
				if($lneutral_cluster[$iclus] && $lneutral_cluster[$jclus]){
					$ncoef_coll_n_n += 1;
				}elsif($lneutral_cluster[$iclus] || $lneutral_cluster[$jclus]){
					if($iclus>$max_cluster || $jclus>$max_cluster){
						$ncoef_coll_n_g += 1;
					}else{
						$ncoef_coll_n_i += 1;
					}
				}else{
					$ncoef_coll_rec += 1;
				}
				
			
				# Add this collision into the flux array
				if(!$l_nonstand && $l_coag==0){
					#reaction coefficients
					$coef_quad{"$iclus,$jclus,$kclus"} = "$coll_coef_temp";
					$coef_quad{"$jclus,$iclus,$kclus"} = "$coll_coef_temp";
					#keeping track of indices
					$ind_quad_loss[$iclus][0] += 1;
					push(@{ $ind_quad_loss[$iclus] },$jclus);
					push(@{ $ind_quad_loss[$iclus] },$kclus);
					if(($iclus!=$jclus) || $lfortran){
						$ind_quad_loss[$jclus][0] += 1;
						push(@{ $ind_quad_loss[$jclus] },$iclus);
						push(@{ $ind_quad_loss[$jclus] },$kclus);
					}
					$ind_quad_form[$kclus][0] += 1;
					push(@{ $ind_quad_form[$kclus] },$iclus);
					push(@{ $ind_quad_form[$kclus] },$jclus);
					if(!$valid && $lout==0 && $kclus!=$n_flux_rec){
						# Brought back from the boundary
						$l_quad_bound{"$iclus,$jclus,$kclus"} = 1;
						$l_quad_bound{"$jclus,$iclus,$kclus"} = 1;
						# Keeping track of the number of products
						$n_coll_products[$iclus][$jclus] = 1;
						# Saving the boundary cluster, if needed
						if($keep_boundary_clusters){
							# See if this boundary cluster is already listed
							# If not, create a new element
							if($str_temp ~~ @label_inc_boundary_clusters){
								$lfound_bound = 0;
								for($i=$max_n_flux;$i<=$max_n_flux_inc_boundary_clusters;$i++){
									if($str_temp eq $label_inc_boundary_clusters[$i]){
										$kclus_bound = $i;
										$lfound_bound = 1;
										#print "Found $str_temp\n";
										last;
									}
								}
								if(!$lfound_bound){
									die "Can't find boundary cluster $str_temp\n";
								}
							}else{
								#print "Adding $str_temp\n";
								$kclus_bound = $max_n_flux_inc_boundary_clusters+1;
								$max_n_flux_inc_boundary_clusters = $kclus_bound;
								$label_inc_boundary_clusters[$kclus_bound] = $str_temp;
								$comments[$kclus_bound]="% Cluster $kclus_bound: $label_inc_boundary_clusters[$kclus_bound], a boundary cluster that is brought back into the system";
                                $num_from_label{"$label_inc_boundary_clusters[$kclus_bound]"} = $kclus_bound;
							}						
							$clus_bound_ind{"$iclus,$jclus,$kclus"} = $kclus_bound;
							$clus_bound_ind{"$jclus,$iclus,$kclus"} = $kclus_bound;					
						}
						# Add the fluxes to monomers into a separate array
						for($imol=0;$imol<$nmol_types;$imol++){
							if($nmonomers{$molecule_name[$imol]} > 0){
								$monomer_clus=$clust_num_of_monomer[$imol];
								if($monomer_clus eq ''){
									die "How can $molecule_name[$imol] evaporate, since it is not included in the system?\n";
								}
								#reaction coefficients
								$coef_quad{"$iclus,$jclus,$monomer_clus"} = $coll_coef_temp;
								$coef_quad{"$jclus,$iclus,$monomer_clus"} = $coll_coef_temp;
								#keeping track of indices
								$ind_quad_loss_extra[$iclus][0] += 1;
								push(@{ $ind_quad_loss_extra[$iclus] },$jclus);
								push(@{ $ind_quad_loss_extra[$iclus] },$monomer_clus);
								push(@{ $ind_quad_loss_extra[$iclus] },$nmonomers{$molecule_name[$imol]});
								$ind_quad_loss_extra[$jclus][0] += 1;
								push(@{ $ind_quad_loss_extra[$jclus] },$iclus);
								push(@{ $ind_quad_loss_extra[$jclus] },$monomer_clus);
								push(@{ $ind_quad_loss_extra[$jclus] },$nmonomers{$molecule_name[$imol]});
								$ind_quad_form_extra[$monomer_clus][0] += 1;
								push(@{ $ind_quad_form_extra[$monomer_clus] },$iclus);
								push(@{ $ind_quad_form_extra[$monomer_clus] },$jclus);
								push(@{ $ind_quad_form_extra[$monomer_clus] },$nmonomers{$molecule_name[$imol]});
								$l_quad_bound{"$iclus,$jclus,$monomer_clus"} = 1;
								$l_quad_bound{"$jclus,$iclus,$monomer_clus"} = 1;
								# Keeping track of the number of products
								$n_coll_products[$iclus][$jclus] += $nmonomers{$molecule_name[$imol]};
								# Marking the boundary cluster also for the monomers
								if($keep_boundary_clusters){
									$clus_bound_ind{"$iclus,$jclus,$monomer_clus"} = $kclus_bound;
									$clus_bound_ind{"$jclus,$iclus,$monomer_clus"} = $kclus_bound;
								}
							}
						}
					}
				}elsif($l_nonstand){
					# Now let's deal with the non-standard reactions.
					# The first product is considered the main one and included in the main flux array.
				
					$coef_temp = $nonstandard_reactions[$iclus][$jclus][1];
					$n_coll_products[$iclus][$jclus] = $coef_temp;
					$kclus=$nonstandard_reactions[$iclus][$jclus][2];
					if($l_print_boundary){
						print "Nonstandard collision: $label[$iclus] + $label[$jclus] -> $coef_temp $label[$kclus]";
					}
				
					#reaction coefficients
					$coef_quad{"$iclus,$jclus,$kclus"} = $coll_coef_temp;
					$coef_quad{"$jclus,$iclus,$kclus"} = $coef_quad{"$iclus,$jclus,$kclus"};
					if($coef_temp == 1){
						$coef_quad_form{"$iclus,$jclus,$kclus"} = $coll_coef_temp;
					}else{
						if($lfortran){
							if($2 =~ m/\./){
								$coef_temp = $coef_temp . "d0";
							}else{
								$coef_temp = $coef_temp . ".d0";
							}
						}
						$coef_quad_form{"$iclus,$jclus,$kclus"} = "$coef_temp*$coll_coef_temp";
					}
					$coef_quad_form{"$jclus,$iclus,$kclus"} = $coef_quad_form{"$iclus,$jclus,$kclus"};
					# Keeping track of the number of products
				
					#keeping track of indices
					$ind_quad_loss[$iclus][0] += 1;
					push(@{ $ind_quad_loss[$iclus] },$jclus);
					push(@{ $ind_quad_loss[$iclus] },$kclus);
					if(($iclus!=$jclus) || $lfortran){
						$ind_quad_loss[$jclus][0] += 1;
						push(@{ $ind_quad_loss[$jclus] },$iclus);
						push(@{ $ind_quad_loss[$jclus] },$kclus);
					}
					$ind_quad_form[$kclus][0] += 1;
					push(@{ $ind_quad_form[$kclus] },$iclus);
					push(@{ $ind_quad_form[$kclus] },$jclus);
				
					# Mark this as a non-standard reaction
					$l_quad_nst{"$iclus,$jclus,$kclus"} = 1;
				
					# Then the other products, these go to the same array as molecules coming from the boundary
					for($icol=3;$icol<$#{ $nonstandard_reactions[$iclus][$jclus] }; $icol+=2){
					
						$coef_temp = $nonstandard_reactions[$iclus][$jclus][$icol];
						# Keeping track of the number of products
						$n_coll_products[$iclus][$jclus] += $coef_temp;
						$kclus=$nonstandard_reactions[$iclus][$jclus][$icol+1];
						if($l_print_boundary){
							print " + $coef_temp $label[$kclus]";
						}
					
						$coef_quad{"$iclus,$jclus,$kclus"} = $coll_coef_temp;
						$coef_quad{"$jclus,$iclus,$kclus"} = $coef_quad{"$iclus,$jclus,$kclus"};
						# If the coefficient is an integer, put it in the collision arrays like for boundary collisions
						if($coef_temp =~ /^\d+$/){
							$coef_quad_form{"$iclus,$jclus,$kclus"} = $coll_coef_temp;
						# otherwise print it with the collision coefficient
						}else{
							if($lfortran){
								$coef_temp = $coef_temp . "d0";
							}
							$coef_quad_form{"$iclus,$jclus,$kclus"} = "$coef_temp*$coll_coef_temp";
							$coef_temp = 1;
						}
						$coef_quad_form{"$jclus,$iclus,$kclus"} = $coef_quad_form{"$iclus,$jclus,$kclus"};
					
						#keeping track of indices
						$ind_quad_loss_extra[$iclus][0] += 1;
						push(@{ $ind_quad_loss_extra[$iclus] },$jclus);
						push(@{ $ind_quad_loss_extra[$iclus] },$kclus);
						push(@{ $ind_quad_loss_extra[$iclus] },$coef_temp);
						$ind_quad_loss_extra[$jclus][0] += 1;
						push(@{ $ind_quad_loss_extra[$jclus] },$iclus);
						push(@{ $ind_quad_loss_extra[$jclus] },$kclus);
						push(@{ $ind_quad_loss_extra[$jclus] },$coef_temp);
						$ind_quad_form_extra[$kclus][0] += 1;
						push(@{ $ind_quad_form_extra[$kclus] },$iclus);
						push(@{ $ind_quad_form_extra[$kclus] },$jclus);
						push(@{ $ind_quad_form_extra[$kclus] },$coef_temp);
					}
					if($l_print_boundary){
						print "\n";
					}
				}else{
					# Now let's deal with the coagulation to formed clusters.
				
					#reaction coefficients
					$coef_quad{"$iclus,$jclus,$kclus"} = "$coll_coef_temp";
					$coef_quad{"$jclus,$iclus,$kclus"} = "$coll_coef_temp";
				
					# $iclus is lost, nothing happens to $jclus or it changes charging state, no new clusters are formed
					#keeping track of indices
					$ind_quad_loss[$iclus][0] += 1;
					push(@{ $ind_quad_loss[$iclus] },$jclus);
					push(@{ $ind_quad_loss[$iclus] },$kclus);
					$ind_quad_form[$kclus][0] += 1;
					push(@{ $ind_quad_form[$kclus] },$iclus);
					push(@{ $ind_quad_form[$kclus] },$jclus);
					if(!$lneutral[$iclus]){
						if($l_coag == 1){
							$kclus = $n_flux_out;
						}elsif($l_coag == 2){
							$kclus = $n_flux_out_neg;
						}else{
							$kclus = $n_flux_out_pos;
						}
						$ind_quad_loss[$jclus][0] += 1;
						push(@{ $ind_quad_loss[$jclus] },$iclus);
						push(@{ $ind_quad_loss[$jclus] },$kclus);
						$ind_quad_form[$kclus][0] += 1;
						push(@{ $ind_quad_form[$kclus] },$iclus);
						push(@{ $ind_quad_form[$kclus] },$jclus);
					}
				}
					
			}	

################################################################################
################################################################################
##      6.3 Save the corresponding evaporation if it can happen               ##
################################################################################
################################################################################

			if($valid_evap){

				# Evaporation coefficient
				$evap_coef_temp= "E($iclus,$jclus)";
			
				#reaction coefficients
				$coef_lin{"$iclus,$jclus,$kclus"} = "$evap_coef_temp";
				$coef_lin{"$jclus,$iclus,$kclus"} = "$evap_coef_temp";
			
				#keeping track of indices
				$ind_lin_form[$iclus][0] += 1;
				push(@{ $ind_lin_form[$iclus] },$jclus);
				push(@{ $ind_lin_form[$iclus] },$kclus);
				if(($iclus!=$jclus) || $lfortran){
					$ind_lin_form[$jclus][0] += 1;
					push(@{ $ind_lin_form[$jclus] },$iclus);
					push(@{ $ind_lin_form[$jclus] },$kclus);
				}
				$ind_lin_loss[$kclus][0] += 1;
				push(@{ $ind_lin_loss[$kclus] },$iclus);
				push(@{ $ind_lin_loss[$kclus] },$jclus);
			
				# Keep track of the number of evaporation processes (needed for mcmc)
				$ncoef_evap += 1;
			}
		} # End of $jclus loop
	
################################################################################
################################################################################
##      6.4 External losses                                                   ##
################################################################################
################################################################################

###########################
## Coagulation sink terms
###########################

		if(!$disable_coag_sinks){
			if(! $lneutral_cluster[$iclus]){
				$cs_term_temp="fcs*";
			}else{
				$cs_term_temp="";
			}
			if($one_cs_for_all){
				$coef_lin{"$n_flux_coag,$n_flux_coag,$iclus"} = $cs_term_temp . "CS";
			}else{
				$coef_lin{"$n_flux_coag,$n_flux_coag,$iclus"} = $cs_term_temp . "CS($iclus)";
			}
			if($lfortran){
				$coef_lin{"$n_flux_coag,$n_flux_coag,$iclus"} =~ s/CS/cs/;
			}
			$ind_lin_loss[$iclus][0] += 1;
			push(@{ $ind_lin_loss[$iclus] },$n_flux_coag);
			push(@{ $ind_lin_loss[$iclus] },$n_flux_coag);
			$ind_lin_form[$n_flux_coag][0] += 1;
			push(@{ $ind_lin_form[$n_flux_coag] },$n_flux_coag);
			push(@{ $ind_lin_form[$n_flux_coag] },$iclus);
		}

###########################
## Wall loss terms
###########################

		if(!$disable_wall_terms){
			if(! $lneutral_cluster[$iclus] && !$l_wl_mcmc){
				$wl_term_temp="fwl*";
			}else{
				$wl_term_temp="";
			}
			$l_special_mcmc_wl[$iclus] = 0;
			if($one_wl_for_all){
				$coef_lin{"$n_flux_wall,$n_flux_wall,$iclus"} = $wl_term_temp . "WL";
			}else{
				$lfound = 0;
				if($#wl_mcmc_only>=0){
					for($icol=0;$icol<=$#wl_mcmc_only;$icol++){
						if(&compare_clusters($label[$iclus],$wl_mcmc_only[$icol])){
							$coef_lin{"$n_flux_wall,$n_flux_wall,$iclus"} = "WL($iclus)";
							$ncoef_wl++;
							$lfound = 1;
							$l_special_mcmc_wl[$iclus] = 1;
							last;
						}
					}
				}
				if(!$lfound){
					$coef_lin{"$n_flux_wall,$n_flux_wall,$iclus"} = $wl_term_temp . "WL($iclus)";
				}
			}
			if($lfortran){
				$coef_lin{"$n_flux_wall,$n_flux_wall,$iclus"} =~ s/WL/wl/;
			}
			$ind_lin_loss[$iclus][0] += 1;
			push(@{ $ind_lin_loss[$iclus] },$n_flux_wall);
			push(@{ $ind_lin_loss[$iclus] },$n_flux_wall);
			$ind_lin_form[$n_flux_wall][0] += 1;
			push(@{ $ind_lin_form[$n_flux_wall] },$n_flux_wall);
			push(@{ $ind_lin_form[$n_flux_wall] },$iclus);
		}

##################
## Dilution loss
##################

		if(!$disable_dilution){
			$coef_lin{"$n_flux_dil,$n_flux_dil,$iclus"} = "dil";
			$ind_lin_loss[$iclus][0] += 1;
			push(@{ $ind_lin_loss[$iclus] },$n_flux_dil);
			push(@{ $ind_lin_loss[$iclus] },$n_flux_dil);
			$ind_lin_form[$n_flux_dil][0] += 1;
			push(@{ $ind_lin_form[$n_flux_dil] },$n_flux_dil);
			push(@{ $ind_lin_form[$n_flux_dil] },$iclus);
		}

###########################
## User-defined sink
###########################

		if(!$disable_input_sink){
			$coef_lin{"$n_flux_insink,$n_flux_insink,$iclus"} = "insink($iclus)";
			$ind_lin_loss[$iclus][0] += 1;
			push(@{ $ind_lin_loss[$iclus] },$n_flux_insink);
			push(@{ $ind_lin_loss[$iclus] },$n_flux_insink);
			$ind_lin_form[$n_flux_insink][0] += 1;
			push(@{ $ind_lin_form[$n_flux_insink] },$n_flux_insink);
			push(@{ $ind_lin_form[$n_flux_insink] },$iclus);
		}

	} # End of $iclus loop
	if($stopping == 1){
		die "Use --nonstandard_reaction_file to specify the outcome of the collisions that haven't been brought back succesfully from the boundary\n";
	}

################################################################################
################################################################################
##      6.5 Finding out the number of MCMC coefficients                       ##
################################################################################
################################################################################

	# number of mcmc collision coefficients
	if($l_mcmc_any){
		$ncoef_coll = 0;
		if($l_coll_factor_mcmc_n_n){
			$ncoef_coll = $ncoef_coll+$ncoef_coll_n_n;
		}
		if($l_coll_factor_mcmc_n_i){
			$ncoef_coll = $ncoef_coll+$ncoef_coll_n_i;
		}
		if($l_coll_factor_mcmc_rec){
			$ncoef_coll = $ncoef_coll+$ncoef_coll_rec;
		}
		if($l_coll_factor_mcmc_n_g){
			$ncoef_coll = $ncoef_coll+$ncoef_coll_n_g;
		}
		if($l_wl_mcmc){
			$ncoef_wl++;
		}
		$n_mcmc_coefs = $ncoef_coll+$ncoef_evap+$l_q_neg_mcmc+$l_q_pos_mcmc+$ncoef_wl;
		if(!$l_use_get_losses && $ncoef_wl>0){
			$l_use_get_losses = 1;
		}
	}

	###		Done with the equations
}

## All terms in the derivative / concentration array are now collected, save the final array size

if($l_save_outgoing_clust){
    $n_out_clust = $n_comp_out;
    $size_C_out += $n_out_clust;
}

# Allocation of isconst, source and fitted, obtained from sources_and_constants
# Problem with the "save" attribute - the size can't be an input parameter in the current implementation
#$size_C_eqn = 'neqn';
$size_C_eqn = $size_C_out;

# Indices of the saved coagulated and outgrown clusters
# Note that these are special cases, since they are NOT explicitly included in the equation terms, but are instead
# deduced from the overall coagulation and outgrowth terms
# Therefore, these are always the last, additional elements in the derivative / concentration array
$i = $max_n_flux;
if($l_save_coag_per_clust){
    $j = $n_coag_per_clust;
    @range_coag_per_clust = ($i+1, $i+$j);
    $i += $j;
}
if($l_save_outgoing_clust){
    $j = $n_out_clust;
    @range_out_clust = ($i+1, $i+$j);
    $i += $j;
}

################################################################################
################################################################################
##      6.6 Time dependent source terms                                       ##
################################################################################
################################################################################

$lines{'source'} = '';
$lines{'source_def'} = '';
if($#source_function>=0){
	$lines{'source'} = "\t% time dependent source terms defined by functions\n";
	if($lfortran){
		$lines{'source'} =~ s/%/!/;
		$lines{'source_def'} = "\treal(kind(1.d0)), external :: ";
	}
	$ii=1;
	for($i=0;$i<=$#source_function;$i++){	
		@columns=split(',',$source_function[$i]);
		$source_function_clust[$i] = $columns[0];
		if ($#columns==1){
			$source_function[$i] = $columns[1];
		}elsif($#columns==0){
			$source_function[$i] = "source_$source_function_clust[$i](t)";
		}else{
			die "Can't understand the source function definition $source_function[$i] - the format should be either 'clust,function name' or 'clust'.\n";
		}
		if($source_function_clust[$i] !~ /^n_j_in$/){
			if(!$lloop){
				$valid=&check_validity($source_function_clust[$i]);
			}else{
				$valid = 1;
				($string1,$string2) = &determine_cluster_composition($source_function_clust[$i]);
				@temp_array=@$string1;
				if($string2 ne '' || sum(@temp_array)>sum(@temp_array[@mol_types_used[1..$nmol_types_used]])){
					# cluster contains molecule types not included in the system
					$valid = 0;
				}
			}
			if(!$valid){
				die "Source term cluster $source_function_clust[$i] is not a valid cluster\n";
			}
			if(!$lloop){
				$iclus=&get_cluster_number($source_function_clust[$i]);
			}elsif($nmol_types_used>1){
				$iclus = "clust_from_indices(".join(',',@temp_array[@mol_types_used[1..$nmol_types_used]]).")";
			}else{
				$imol=1;
				$iclus = $temp_array[$mol_types_used[$imol]];
			}
		}else{
			$iclus = $source_function_clust[$i];
			if($lloop_j_tests){
				$lines{'source'} .= "\tif (use_jtable) then\n";
				if($temperature =~ m/\./){
					$str_temp = $temperature . "d0";
				}else{
					$str_temp = $temperature . ".d0";
				}
				if($rh =~ m/\./){
					$str_temp2 = $rh . "d0/100.d0";
				}else{
					$str_temp2 = $rh . ".d0/100.d0";
				}
				$lines{'source'} .= "\t\tcs_for_table = loss(1)+sum(K(1,n_j_in:nclust)*c(n_j_in:nclust))\n";
				$lines{'source'} .= "\t\tcall interp_J_table($str_temp,$str_temp2,cs_for_table,c(1)*1.d-6,0.d0,j_temp)\n";
				$lines{'source'} .= "\t\tj_temp = j_temp*1.d6\n";
				$lines{'source'} .= "\t\tif (use_KK) then\n";
				$lines{'source'} .= "\t\t\tif (r_j_init*1.d-9 .ge. $rlim_growth_compound_str) then\n";
				$lines{'source'} .= "\t\t\t\twrite(*,*) 'Add the growth compound to the KK extrapolation!'\n";
				$lines{'source'} .= "\t\t\t\tstop\n";
				$lines{'source'} .= "\t\t\tend if\n";
				$temp_val = sprintf('%.14e',$mass[0]/$density[0]);
				$temp_val =~ s/e/d/g;
				$lines{'source'} .= "\t\t\tgr = (6.d0*$temp_val/pi)**(1.d0/3.d0)/3.d0/n_j_init**(2.d0/3.d0)*K(1,n_j_init)*c(1)\n";
				$lines{'source'} .= "\t\t\tcoags = loss(n_j_init)+sum(K(n_j_init,n_j_in:nclust)*c(n_j_in:nclust))\n";
				$lines{'source'} .= "\t\t\tsource(n_j_in) = extrapolate_J(r_j_init*1.d-9,r_j_in*1.d-9,j_temp,gr,coags)\n";
				$lines{'source'} .= "\t\telse\n";
				$lines{'source'} .= "\t\t\tsource(n_j_in) = j_temp\n";
				$lines{'source'} .= "\t\tend if\n";
				$lines{'source'} .= "\telse\n\t";
			}
		}
		print "\n---------------------------------------------------------\n";
		print "\tYou will need the function $source_function[$i]\n\tin order to compile and run the code.\n";
		print "---------------------------------------------------------\n\n";
		$lines{'source'} .= "\tsource($iclus) = $source_function[$i];\n";
		if($lloop_j_tests && $iclus =~ /^$source_function_clust[$i]$/){
			$lines{'source'} .= "\tend if\n";
		}
		if($lfortran){
			if($ii==4){
				$lines{'source_def'} =~ s/, $//;
				$lines{'source_def'} .= "\n\treal(kind(1.d0)), external :: ";
				$ii = 1;
			}
			$str_temp = $source_function[$i];
			$str_temp =~ s/\(\S+\)$//;
			$lines{'source_def'} .= "$str_temp, ";
			$ii++;
		}
	}
	$lines{'source'} .= "\n";
	if($lfortran){
		$lines{'source'} =~ s/;//g;
		$lines{'source_def'} =~ s/, $/\n/;
		if($lloop_j_tests && $l_j_in){
			$lines{'source_def'} .= "\texternal :: interp_J_table\n";
			$lines{'source_def'} .= "\treal(kind(1.d0)), external :: extrapolate_J\n";
		}
	}else{
		$lines{'source'} =~ s/\t//g;
	}
}

################################################################################
################################################################################
##      6.7 Reactions inside clusters                                         ##
################################################################################
################################################################################

if($l_reac_in_clus){
	open(CRFILE, "<$reactions_in_clusters_file") || die "\nCould not open the cluster reaction file $reactions_in_clusters_file\n\n";
	chomp(@cluster_reactions=<CRFILE>);
	close(GFILE);
	$number_of_lines=$#cluster_reactions+1;
	REACTIONLINES: for($iline=0;$iline<$number_of_lines;$iline++){
		# Reading lines from the cluster reaction file
		@columns = split(' ',$cluster_reactions[$iline]);
		# First two entries: number of reactants and number of products
		$n_react = $columns[0];
		$n_prod = $columns[1];
		# Numbers of water molecules participating in the reaction as reactants, products or catalysts
		$n_reacting_W = 0;
		$n_formed_W = 0;
		$n_catalyzing_W = 0;
		$l_forbidden_W = 0;
		# empty cluster composition array corresponding to the set of reacting molecules and the set of product molecules
		for($imol=0;$imol<$nmol_types;$imol++){
			$comp_react[$imol] = 0;
			$comp_prod[$imol] = 0;
		}
		# Checking that we have the reactant molecules in the system ...
		for($icol=2;$icol<=$n_react+1;$icol++){
			if($lhydrate_average && $columns[$icol] eq $name_water){
				$n_reacting_W += 1;
				next;
			}elsif(! exists $mol_num_from_name{$columns[$icol]}){
				print "The reactant $columns[$icol] on line ".($iline+1)." of the cluster reaction file is not a valid molecule. -> Ignoring the reaction.\n\n";
				next REACTIONLINES;
			}
			# ... and adding them to the cluster composition array corresponding to the reacting molecules unless they are hydration waters
			$comp_react[$mol_num_from_name{$columns[$icol]}] += 1;
		}
		# Checking that we have the product molecules in the system ...
		for($icol=2+$n_react;$icol<=$n_react+$n_prod+1;$icol++){
			if($lhydrate_average && $columns[$icol] eq $name_water){
				$n_formed_W += 1;
				next;
			}elsif(! exists $mol_num_from_name{$columns[$icol]}){
				print "The product $columns[$icol] on line ".($iline+1)." of the cluster reaction file is not a valid molecule. -> Ignoring the reaction.\n\n";
				next REACTIONLINES;
			}
			# ... and adding them to the cluster composition array corresponding to the produced molecules unless they are hydration waters
			$comp_prod[$mol_num_from_name{$columns[$icol]}] += 1;
		}
		$rate_fwd = $columns[$n_react+$n_prod+2];
		$rate_bck = $columns[$n_react+$n_prod+3];
		@needed_mols = ();
		@forbidden_mols = ();
		for($icol=$n_react+$n_prod+4;$icol<=$#columns;$icol++){
			if($columns[$icol] =~ /^!/){
				$temp_val = $columns[$icol];
				$temp_val =~ s/!//;
				if(exists $mol_num_from_name{$temp_val}){
					push(@forbidden_mols,$mol_num_from_name{$temp_val});
				# Water is treated separately when the $lhydrate_average option is used
				}elsif(($columns[$icol] eq $name_water) && $lhydrate_average && ($pw>0)){
					$l_forbidden_W = 1;
				}
			}else{
				if(exists $mol_num_from_name{$columns[$icol]}){
					push(@needed_mols,$mol_num_from_name{$columns[$icol]});
				# Water is treated separately when the $lhydrate_average option is used
				}elsif(($columns[$icol] eq $name_water) && $lhydrate_average && ($pw>0)){
					$n_catalyzing_W += 1;
				}else{
					print "The catalyzing molecule $columns[$icol] on line ".($iline+1)." of the cluster reaction file is not a valid molecule. -> Ignoring the reaction.\n\n";
					next REACTIONLINES;
				}
			}
		}
		# Going through all clusters
		for($iclus=1;$iclus<=$max_cluster;$iclus++){
			# checking both directions of the reaction
			DIRECTIONS: for($i=1;$i<=2;$i++){
				@temp_array = @{ $clust_comp[$iclus] };
				if($i==2){
					@temp_array_2 = @comp_react;
					@comp_react = @comp_prod;
					@comp_prod = @temp_array_2;
					$temp_val = $rate_fwd;
					$rate_fwd = $rate_bck;
					$rate_bck = $temp_val;
					$temp_val = $n_reacting_W;
					$n_reacting_W = $n_formed_W;
					$n_formed_W = $temp_val;
				}
				# checking if the cluster contains the reactants of this reaction (i.e. products of the initial reaction for $i=2)
				for($imol=0;$imol<$nmol_types;$imol++){
					$temp_array[$imol] -= $comp_react[$imol];
					if($temp_array[$imol]<0){
						next DIRECTIONS;
					}
				}
				
				
				# checking if it in addition contains the other needed (catalyzing) molecules
				@temp_array_2 = @temp_array;
				for($icol=0;$icol<=$#needed_mols;$icol++){
					$temp_array_2[$needed_mols[$icol]] -= 1;
					if($temp_array_2[$needed_mols[$icol]]<0){
						next DIRECTIONS;
					}
				}
				# if there are hydrate-averaged waters as catalyzing molecules, check that the cluster has enough hydrate
				if($lhydrate_average && $#{ $distr[$iclus] }<$n_catalyzing_W){
					next DIRECTIONS;
				}
				# checking that it doesn't contain the forbidden molecules (other than possibly hydration water)
				for($icol=0;$icol<=$#forbidden_mols;$icol++){
					if($temp_array_2[$forbidden_mols[$icol]]>0){
						next DIRECTIONS;
					}
				}
				
				# determining the new (dry) cluster and checking if it is a valid one
				for($imol=0;$imol<$nmol_types;$imol++){
					$temp_array[$imol] += $comp_prod[$imol];
				}
				$label = &create_label(\@temp_array);
				$jclus=&get_cluster_number($label);
				if($jclus eq ''){
					next DIRECTIONS;
				}
				
				# now we have a product, last thing to save it, unless we already have a higher rate for the process
				if(!exists $coef_reac{"$iclus,$jclus"}){
					$coef_reac{"$iclus,$jclus"} = 0;
					if($lhydrate_average){
						for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
							$coef_reac{"$iclus,$jclus,$ihydr"} = 0;
						}
					}
					#keeping track of indices if this is a new reaction
					$ind_reac_form[$jclus][0] += 1;
					push(@{ $ind_reac_form[$jclus] },$n_react_in_clust);
					push(@{ $ind_reac_form[$jclus] },$iclus);
					$ind_reac_loss[$iclus][0] += 1;
					push(@{ $ind_reac_loss[$iclus] },$jclus);
					push(@{ $ind_reac_loss[$iclus] },$n_react_in_clust);
				}
				if(!$lhydrate_average){
					if($rate_fwd>$coef_reac{"$iclus,$jclus"}){
						# save reaction coefficient
						$coef_reac{"$iclus,$jclus"} = "$rate_fwd";
					}
				}else{
					# when hydrates are used, keep track of the minimum/maximum numger of waters in the initial cluster
					for($ihydr=$n_reacting_W;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
						if(($ihydr>=$n_reacting_W + $n_catalyzing_W) && !$l_forbidden_W && $rate_fwd>$coef_reac{"$iclus,$jclus,$ihydr"}){
							$coef_reac{"$iclus,$jclus,$ihydr"} = $rate_fwd;
						}
					}
				}
			}
		}
	}
	if(!$lfortran){
		open(REAC, ">get_reac$append_to_file_names.m");
#		if($variable_temp){
#			print REAC "function R = get_reac(temperature)\n\n";
#		}
		print REAC "% Reaction coefficients for chemical reactions inside clusters\n\n";
		print REAC "R = nan($max_cluster_number,$max_cluster_number);\n\n";
		for($iclus=1;$iclus<=$max_cluster;$iclus++){
			for($jclus=$iclus+1;$jclus<=$max_cluster;$jclus++){
				print "$iclus, $jclus, ".$coef_reac{"$iclus,$jclus"}."\n";
				if(exists $coef_reac{"$iclus,$jclus"}){
					$string1 = '';
					$string2 = '';
					# calculating the hydrate averaged rates
					if($lhydrate_average){
						$string1 .= ', hydrate average: ';
						$string2 .= ', hydrate average: ';
						for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
							$coef_reac{"$iclus,$jclus"} += $distr[$iclus][$ihydr]*$coef_reac{"$iclus,$jclus,$ihydr"};
							$string1 .= sprintf("%.2f",$distr[$iclus][$ihydr])."*".$coef_reac{"$iclus,$jclus,$ihydr"}."+";
						}
						$string1 =~ s/\+$//;
						for($jhydr=0;$jhydr<=$#{ $distr[$jclus] };$jhydr++){
							$coef_reac{"$jclus,$iclus"} += $distr[$jclus][$jhydr]*$coef_reac{"$jclus,$iclus,$jhydr"};
							$string2 .= sprintf("%.2f",$distr[$jclus][$jhydr])."*".$coef_reac{"$jclus,$iclus,$jhydr"}."+";
						}
						$string2 =~ s/\+$//;
					}
					print REAC "R($iclus,$jclus) = ".$coef_reac{"$iclus,$jclus"}.";\t% $label[$iclus] -> $label[$jclus]$string1\n";
					print REAC "R($jclus,$iclus) = ".$coef_reac{"$jclus,$iclus"}.";\t% $label[$jclus] -> $label[$iclus]$string2\n\n";
				}
			}
		}
#		if($variable_temp){
#			print REAC "\nend";
#		}
		close(REAC);
	}
}
		

################################################################################
################################################################################
##   7. Reading the cluster radius file                                       ##
################################################################################
################################################################################

### Reading in the radii, if we are not using bulk densities

if(!$l_bulk_density){
	open(RADII, "<$radius_file_name") || die "\nCould not open radius file $radius_file_name\n\n";
	chomp(@radius_data=<RADII>);
	close(RADII);
	$number_of_lines=$#radius_data+1;
	for($iline=0;$iline<$number_of_lines;$iline++){
		next if ($radius_data[$iline] =~ /^\#/);
		if($radius_data[$iline] =~ /^\s*(\S+)\s+(\S+)/){

			$temp_label=$1;

			# Checking if we have the cluster (or the corresponding dry one 
			# if we are using hydrates) in the system
			($iclus,$nwaters)=&get_corresponding_dry($temp_label);
			
			# save the radius value if we have the cluster in the system
			if($iclus ne ''){
				if(!&is_pos_number($2)){
					die "The radius given for cluster $label[$iclus] is not a number!\n";
				};
				# Each cluster must appear only once in the radius file, so the radius should not be defined yet
				if(exists $clust_radius[$iclus][$nwaters]){
					die "Radius of cluster $temp_label is multiply defined in the radius file $radius_file_name.\n";
				}
				$clust_radius[$iclus][$nwaters] = $2*1.0e-9;	# convert from nm to m
			}
		}
	}
	# Now all the cluster should have a radius value
	for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
		for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
			if(!(exists $clust_radius[$iclus][$ihydr])){
				if($ihydr==0){
					die "\nRadius not found in $radius_file_name for $label[$iclus]!\n\n";
				}else{
					die "\nRadius not found in $radius_file_name for $label[$iclus]$ihydr$name_water!\n\n";
				}
			}
		}
	}
}

################################################################################
################################################################################
##   8. Starting to print the output files                                    ##
################################################################################
################################################################################

################################################################################
################################################################################
##      8.1 Cluster properties for Matlab driver and Fortran system file      ##
################################################################################
################################################################################

if($lfortran){
	open(SYST, ">$system_file_name_fortran") || die "\nCould not open system file $system_file_name_fortran\n\n";
	print SYST "module acdc_system$append_to_syst_names\n\nimplicit none\n\n";
    if($tag !~ /^\s*$/){
        $str_temp = $tag;
    }else{
        $str_temp = "''";
    }
    print SYST "character(len=*), parameter :: tag = $str_temp\t\t\t! tag for the simulation system\n\n";
	if(!$lloop){
        print SYST "logical, parameter :: small_set_mode = .true.\t\t\t! small set of clusters (default mode)\n\n";
		print SYST "integer, parameter :: nclust = $max_cluster_number\t\t\t\t\t\t! number of clusters, molecules and ions\n";
		print SYST "integer, parameter :: neq = $size_C_out\t\t\t\t\t\t\t! number of equations\n";
		print SYST "integer, parameter :: nclust_max = $max_cluster_number, neq_max = $size_C_out\t! same as nclust and neq in the small set mode\n";
	}else{
        print SYST "logical, parameter :: small_set_mode = .false.\t\t\t\t\t\t\t! very large set of clusters (loop mode)\n\n";
		# Name the system size parameters in a different way in the module to avoid confusion and errors when allocating arrays in drivers etc.,
		# as the loop system may be restricted
		if($lloop_restrict){
			print SYST "integer, parameter :: nclust = -1, neq = -1\t\t\t\t\t\t! not pre-determined in the restrict mode\n";
			print SYST "logical, parameter :: restrict_system = .true.\t\t\t\t\t\t\t! exclude given cluster compositions\n";
		}else{
			print SYST "integer, parameter :: nclust = $max_cluster_number, neq = $size_C_out\n";
			print SYST "logical, parameter :: restrict_system = .false.\t\t\t\t\t\t\t! all cluster compositions allowed\n";
		}
        print SYST "integer, parameter :: nclust_max = $max_cluster_number\t\t\t\t\t\t! max. number of clusters, molecules and ions\n";
		print SYST "integer, parameter :: neq_max = $size_C_out\t\t\t\t\t\t\t! max. number of equations\n";
	}
	if($l_jlim){
		print SYST "\ninteger, parameter :: nlim = $nlim\t\t\t\t\t\t\t! number of limits over which the net flux is recorded\n";
		print SYST "real(kind(1.d0)), parameter :: r_lim(nlim) = (/$jlim_sizes_list/)*1.d-9\n";
	}
	print SYST "\n";
	if($l_mcmc_any){
		print SYST "integer, parameter :: ncoefs = " . ($n_mcmc_coefs) . "\t\t\t\t\t\t! number of mcmc coefficients\n";
		print SYST "integer, parameter :: ncoefs_coll = " . ($ncoef_coll) . "\t\t\t\t! number of sticking coefficients\n";
		print SYST "integer, parameter :: ncoefs_evap = " . ($ncoef_evap) . "\t\t\t\t! number of evaporation coefficients\n";
		if($l_q_neg_mcmc){
			print SYST "integer, parameter :: n_q_neg_coef = " . ($ncoef_coll+$ncoef_evap+1) . "\t\t\t\t! mcmc coefficient corresponding to Q_neg\n";
		}
		if($l_q_pos_mcmc){
			print SYST "integer, parameter :: n_q_pos_coef = " . ($ncoef_coll+$ncoef_evap+$l_q_neg_mcmc+1) . "\t\t\t\t! mcmc coefficient corresponding to Q_pos\n";
		}
		if($ncoef_wl>0){
			print SYST "integer, parameter :: n_wl_coefs = $ncoef_wl\t\t\t\t\t! mcmc coefficient corresponding to the wall loss term\n";
		}
		print SYST "\n";
	}
	print SYST "integer, parameter :: n_variables = $n_variable_parameters\n";
	if($variable_temp){
		print SYST "logical, parameter :: variable_temp = .true.\n";
	}else{
		print SYST "logical, parameter :: variable_temp = .false.\n";
        if(!$no_ambient_params_in_syst){
            if($temperature =~ m/\./){
                $str_temp = "";
            }else{
                $str_temp = ".";
            }
            print SYST "real(kind(1.d0)), parameter :: temp = $temperature" . $str_temp . "d0\t\t\t\t! temperature in K\n";
        }
	}
    if($variable_cs){
        print SYST "logical, parameter :: variable_cs = .true.\n";
    }else{
        print SYST "logical, parameter :: variable_cs = .false.\n";
    }
    if(!$disable_coag_sinks){
        if($coag_terms =~ m/^exp_loss$/i){
            $str_temp = sprintf('%.14e',$exp_loss_exponent);
            $str_temp =~ s/e/d/;
            print SYST "real(kind(1.d0)), parameter :: cs_exponent_default = $str_temp\t\t\t! parameters for the exponential loss\n";
            $str_temp = sprintf('%.14e',$exp_loss_coefficient);
            $str_temp =~ s/e/d/;
            print SYST "real(kind(1.d0)), parameter :: cs_coefficient_default = $str_temp\n";
        }elsif($coag_terms =~ m/^bg_loss$/i){
            $str_temp = sprintf('%.14e',$bg_concentration);
            $str_temp =~ s/e/d/;
            print SYST "real(kind(1.d0)), parameter :: cbg_default = $str_temp\t\t\t! default properties of the scavengers (in SI units)\n";
            $str_temp = sprintf('%.14e',$bg_diameter);
            $str_temp =~ s/e/d/;
            print SYST "real(kind(1.d0)), parameter :: dpbg_default = $str_temp\n";
            $str_temp = sprintf('%.14e',$bg_density);
            $str_temp =~ s/e/d/;
            print SYST "real(kind(1.d0)), parameter :: rhobg_default = $str_temp\n";
        }
    }
    if($variable_ion_source){
        print SYST "logical, parameter :: variable_ipr = .true.\n";
    }else{
        print SYST "logical, parameter :: variable_ipr = .false.\n";
    }
    if(!$no_ambient_params_in_syst){
        if($rh =~ m/\./){
            $str_temp = "";
        }else{
            $str_temp = ".";
        }
        print SYST "real(kind(1.d0)), parameter :: rh = $rh" . $str_temp . "d0\t\t\t\t\t! RH in %\n";
        if($pw =~ m/\./){
            $str_temp = "";
        }else{
            $str_temp = ".";
        }
        print SYST "real(kind(1.d0)), parameter :: pw = $pw" . $str_temp . "d0\t\t\t\t\t! partial pressure of water in Pa\n";
    }
	print SYST "\n";
	
	print SYST "integer, parameter :: n_monomer_types = $nmolecules\n";
	print SYST "integer, parameter :: n_charges = $ncharges\t\t\t! number of charging states\n";
	
	if(!$lloop){
		print SYST "integer, parameter :: ";
		for($imol=1;$imol <= $nmolecules;$imol++){
			if($imol>1){
				print SYST ", ";
			}
			print SYST "n$label[$molecules[$imol]] = $molecules[$imol]";
		}
		if($include_generic_neg){
			print SYST ", n$label[$n_generic_neg] = $n_generic_neg";
		}
		if($include_generic_pos){
			print SYST ", n$label[$n_generic_pos] = $n_generic_pos";
		}
		print SYST "\t\t\t! cluster indices for monomers and ions\n";
		
		if($l_save_outgoing){
			print SYST "\n";
			$str_temp = "(/$n_flux_out, ";
			if($include_negative_ion_terms){
				$str_temp .= "$n_flux_out_neg, ";
			}
			if($include_positive_ion_terms){
				$str_temp .= "$n_flux_out_pos, ";
			}
			$str_temp =~ s/, $//;
			$str_temp .= "/)";
			$str_temp =  "integer, parameter :: nout_all($ncharges) = " . $str_temp;
			$str_temp .=  ", ";
			for($k=$n_flux_out; $k<=$n_flux_out_max; $k++){
				$str_temp .= "n$label[$k] = $k, ";
			}
			$str_temp =~ s/, $//;
			print SYST "$str_temp\t\t\t! indices for outgoing fluxes\n\n";
		}
        print SYST "integer, parameter :: nclust_coag_saved = $n_coag_per_clust\t\t\t! number of saved scavenged clusters\n";
        print SYST "integer, parameter :: nclust_out_saved = $n_out_clust\t\t\t\t! number of saved outgrown clusters\n";
        print SYST "integer, parameter :: nrange_coag_saved(2) = (/$range_coag_per_clust[0], $range_coag_per_clust[1]/)	! index range of saved scavenged clusters\n";
        print SYST "integer, parameter :: nrange_out_saved(2) = (/$range_out_clust[0], $range_out_clust[1]/)	! index range of saved outgrown clusters\n";
	}else{
		if(!$lloop_restrict && !$lloop_cs){
			print SYST "integer, parameter :: nout_all($ncharges) = $n_flux_out\t\t\t! indices for outgoing fluxes\n";
		}else{
			print SYST "integer, parameter :: nout_all($ncharges) = -1\t\t\t! not pre-determined\n";
		}
	}
	print SYST "\n";
	
	print SYST "integer, parameter :: n_mol_types = $nmol_types_used\n";
	print SYST "integer, parameter :: ";
	for($imol=1;$imol<=$nmol_types_used;$imol++){
		if($imol>1){
			print SYST ", ";
		}
		print SYST "nmol$mol_names_used[$imol] = $imol";
	}
	print SYST "\t\t\t! molecule indices for the used species\n\n";
	
}else{
	
	open(DRIVER, ">$driver_file_name") || die "\nCould not open driver $driver_file_name.\n\n";
	
	# print some explanations in the beginning
	if($l_old_output){
		print DRIVER "function [C, T, clust, Cf, J_out, flux, out, outflux_matrix, sources, form, converged] = $driver_function_name(Tmax, varargin)\n";
		print DRIVER "%function [C, T, clust, Cf, J_out, flux, out, outflux_matrix, sources, form, converged] = $driver_function_name(Tmax, {C0, {T0}}, {'Option', {Value}, {...}}))\n";
	}else{
		print DRIVER "function [C, T, converged, clust, Cf, varargout] = $driver_function_name(Tmax, varargin)\n";
		print DRIVER "%function [C, T, converged, clust, Cf, labels_ch, clust_flux, J_out, flux, outflux_matrix, out, sources] = $driver_function_name(Tmax, {C0, {T0}}, {'File', Filename, {...}}))\n";
		print DRIVER "%function [C, T, converged, clust, Cf, ~, ~, J_out] = $driver_function_name(Tmax, {C0, {T0}}, 'no_dofluxes',  {'Option', {Value}, {...}}))\n";
		print DRIVER "%function [C, T, converged, clust, Cf] = $driver_function_name(Tmax, {C0, {T0}}, 'no_fluxes',  {'Option', {Value}, {...}}))\n";
	}
	
	print DRIVER "% \n";
	print DRIVER "% Input parameters:\n";
	print DRIVER "% Tmax:		     duration of the simulation in seconds (added to T0), or vector containing output time points (not added to T0).\n";
	print DRIVER "% C0:			 an optional row vector (or matrix) containing the initial concentrations (on the last row).\n";
	print DRIVER "% T0:			 if C0 contains concentrations as a function of time, the corresponding times should be given in the column vector T0.\n";
    print DRIVER "% The rest of optional input parameters are given either as a single keyword (e.g. 'no_fluxes' or 'repeat'), or pairs of keyword and value\n% (e.g. 'Sources_in', filename or 'Options', string); see the ACDC Technical manual for a list of available parameters\n";
	if($variable_temp){
		print DRIVER "% 'Temperature', number:	   temperature if not $temperature K\n";
	}
	print DRIVER "% \n";
	print DRIVER "% Output parameters:\n";
	print DRIVER "% C:			  cluster distribution in cm^(-3) as a function of time T\n";
	print DRIVER "% T:			  time points (seconds) corresponding to C\n";
	if(!$l_old_output){
		print DRIVER "% converged:	  1 if the simulation has converged, and 0 if not, and -1 if there are negative concentrations lower than a threshold value\n";
	}
	print DRIVER "% clust:		  cluster names\n";
	print DRIVER "% Cf:          final cluster distribution in cm^(-3)\n";
	print DRIVER "% labels_ch:	  names of the neutral and charged forms of all molecules, removed or extra protons and generic ions\n";
	print DRIVER "% clust_flux:	  names for all fluxes, including also non-clusters (sources, losses etc.)\n";
	print DRIVER "% J_out:       particle formation rate (rate out of the system) in cm^(-3) s^(-1) as a function of time\n";
	print DRIVER "% flux:        net fluxes from i to j (cm^(-3) s^(-1)) are given in the matrix elements flux(i,j)\n";
	print DRIVER "%              in collisions/fissions involving two similar clusters, the flux is from the point of view of the\n";
	print DRIVER "%              SMALLER cluster, i.e. must be divided by 2 when considering the point of view of the larger cluster\n";
	print DRIVER "% outflux_matrix:	  fluxes going out of the system by collision of clusters i and j (cm^(-3) s^(-1)) \n";
	print DRIVER "%     		  are given in the matrix elements outflux_matrix(i,j)\n";
	print DRIVER "%     		  for i=j, the flux is from the point of view of the outgrowing clusters (i.e. does NOT need to be divided by 2)\n";
	print DRIVER "% out:         fluxes from i out to a cluster with j mol1 (cm^(-3) s^(-1)) are in out(i,j+1,k) with\n";
	print DRIVER "%     		  k=1: neutral, k=2: neg, k=3: pos, k=4: recombination\n";
	print DRIVER "%     		  in collisions involving two similar clusters, the flux is from the point of view of \n";
	print DRIVER "%     		  the outgrowing clusters (i.e. does NOT need to be divided by 2)\n";
	print DRIVER "% sources:	  sources of each species (cm^(-3) s^(-1))\n";
#	print DRIVER "% form:	      formation rates of clusters with j mol1 in the system (cm^(-3) s^(-1)); \n";
#	print DRIVER "%     		  DO NOT trust this 100% because it hasn't really been used or tested\n";
	if($l_old_output){
		print DRIVER "% converged:	  1 if the simulation has converged, 0 if not, and -1 if there are negative concentrations lower than a threshold value\n\n";
	}

}

if(!$lloop){
	# Printing info on the cluster set to the output files
	$lines{'nof1'} = "";	# Number of molecules of the first type in each cluster (including possible ionized form)
	$lines{'1of1'} = "";	# Indices of electrically neutral clusters containing one molecule of the first type
	$lines{'0'} = "";	# Indices of all electrically neutral species
	$lines{'n'} = "";	# Indices of all negative species
	$lines{'p'} = "";	# Indices of all positive species
	$lines{'0m'} = "";	# Indices of electrically neutral monomers
	$lines{'nm'} = "";	# Indices of negative monomers
	$lines{'pm'} = "";	# Indices of positive monomers
	$lines{'0c'} = "";	# Indices of electrically neutral clusters
	$lines{'nc'} = "";	# Indices of negative clusters
	$lines{'pc'} = "";	# Indices of positive clusters
	$lines{'cst'} = "";	# Charging states (1 = neutral, 2 = negative, 3 = positive)
	$lines{'m'} = "";	# Masses
	$lines{'d'} = "";	# Mass diameters
	$lines{'dm'} = "";	# Mobility diameters
	$lines{'cl'} = "";	# Cluster names
	$lines{'mon'} = "";	# Indices of monomers
	$lines{'nmon'} = "";	# Indices of non-monomer clusters
	$lines{'t0'} = "";	# Indices for the table output (neutral)
	$lines{'tn'} = "";	# Indices for the table output (negative)
	$lines{'tp'} = "";	# Indices for the table output (positive)
	$lines{'out0'} = "";	# Criteria for clusters growing out of the system (neutral)
	$lines{'outn'} = "";	# Criteria for clusters growing out of the system (negative)
	$lines{'outp'} = "";	# Criteria for clusters growing out of the system (positive)
	$i = 0;
	$j = 0;
	$k = 0;
	$l = 0;
	$ii = 0;
	$jj = 0;
	$kk = 0;
	$ll = 0;
	$jm = 0;
	$km = 0;
	$lm = 0;
	$jc = 0;
	$kc = 0;
	$lc = 0;
	$jclus = 0;
	$clust_mass_max = 0;
	$diameter_max = 0;
	$mob_diameter_max = 0;
	for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
		$lines{'cl'} .= "'" . $label[$iclus] . "' ";
		if($lmonomer[$iclus]){
			$lines{'mon'} .= "$iclus ";
		}else{
			$lines{'nmon'} .= "$iclus ";
		}
		if($jclus==10){
			$lines{'nof1'} .= "&\n\t\t&";
			$lines{'cst'} .= "&\n\t\t&";
			$lines{'m'} .= "&\n\t\t&";
			$lines{'d'} .= "&\n\t\t&";
			$lines{'dm'} .= "&\n\t\t&";
			$jclus = 0;
		}
		$jclus += 1;
		$mass1 = $clust_mass[$iclus][0];
		$mass1 = sprintf("%.2f",$mass1/$mass_conv);
		$clust_mass_max = max($clust_mass_max,$mass1);
		$mass1 =~ s/e/d/;
		$lines{'m'} .= "$mass1, ";
		$radius = $clust_radius[$iclus][0];
		$diameter = sprintf("%.2f",$radius*2e9);
		$diameter_max = max($diameter_max,$diameter);
		$diameter =~ s/e/d/;
		$lines{'d'} .= "$diameter, ";
		$diameter = sprintf("%.2f",(2.0e9*$radius+0.3)*sqrt(1+28.8*$mass_conv/$mass1));
		$mob_diameter_max = max($mob_diameter_max,$diameter);
		$diameter =~ s/e/d/;
		$lines{'dm'} .= "$diameter, ";
		if($lneutral_cluster[$iclus]){
			$lines{'cst'} .= "1, ";
			if($clust_comp[$iclus][0] == 1){
				if($ii==15){
					$lines{'1of1'} .= "&\n\t\t&";
					$ii = 0;
				}
				$lines{'1of1'} .= "$iclus, ";
				$i += 1;
				$ii += 1;
			}
			if($jj==20){
				$lines{'0'} .= "&\n\t\t&";
				$lines{'0c'} .= "&\n\t\t&";
				$jj = 0;
			}
			$lines{'0'} .= "$iclus, ";
			if($lmonomer[$iclus]){
				$lines{'0m'} .= "$iclus, ";
				$jm += 1;
			}else{
				$lines{'0c'} .= "$iclus, ";
				$jc += 1;
			}
			$j += 1;
			$jj += 1;
			$jmol = 1;
			$nmol = 1;
			for($n=1;$n<$n_neutral_mols;$n++){
				$imol = $neutral_mols[$n];
				$jmol = $jmol+$nmol*$clust_comp[$iclus][$imol];
				$nmol = $nmol*($n_max_type[$imol]+1);
			}
			$lines{'nof1'} .= "$clust_comp[$iclus][0], ";
			$lines{'t0'} .= "\[" . ($clust_comp[$iclus][0]+1) . " $jmol\] ";
		}elsif($lnegative_cluster[$iclus]){
			$lines{'cst'} .= "2, ";
			if($kk==15){
				$lines{'n'} .= "&\n\t\t&";
				$lines{'nc'} .= "&\n\t\t&";
				$kk = 0;
			}
			$lines{'n'} .= "$iclus, ";
			if($lmonomer[$iclus]){
				$lines{'nm'} .= "$iclus, ";
				$km += 1;
			}else{
				$lines{'nc'} .= "$iclus, ";
				$kc += 1;
			}
			$k += 1;
			$kk += 1;
			$jmol = 1;
			$nmol = 1;
			for($n=1;$n<$n_neutral_mols;$n++){
				$imol = $neutral_mols[$n];
				$jmol = $jmol+$nmol*$clust_comp[$iclus][$imol];
				if($n_corr_negative_mol[$imol] > 0){
						$jmol = $jmol+$nmol*$clust_comp[$iclus][$n_corr_negative_mol[$imol]];
				}
				$nmol = $nmol*($n_max_type_neg[$imol]+1);
			}
			if($first_neg>0){
				$lines{'nof1'} .= ($clust_comp[$iclus][0]+$clust_comp[$iclus][$first_neg]) . ", ";
				$lines{'tn'} .= "\[" . ($clust_comp[$iclus][0]+$clust_comp[$iclus][$first_neg]+1) . " $jmol\] ";
			}else{
				$lines{'nof1'} .= "$clust_comp[$iclus][0], ";
				$lines{'tn'} .= "\[" . ($clust_comp[$iclus][0]+1) . " $jmol\] ";
			}
		}elsif($lpositive_cluster[$iclus]){
			$lines{'cst'} .= "3, ";
			if($ll==15){
				$lines{'p'} .= "&\n\t\t&";
				$lines{'pc'} .= "&\n\t\t&";
				$ll = 0;
			}
			$lines{'p'} .= "$iclus, ";
			if($lmonomer[$iclus]){
				$lines{'pm'} .= "$iclus, ";
				$lm += 1;
			}else{
				$lines{'pc'} .= "$iclus, ";
				$lc += 1;
			}
			$l += 1;
			$ll += 1;
			$jmol = 1;
			$nmol = 1;
			for($n=1;$n<$n_neutral_mols;$n++){
				$imol = $neutral_mols[$n];
				$jmol = $jmol+$nmol*$clust_comp[$iclus][$imol];
				if($n_corr_positive_mol[$imol] > 0){
						$jmol = $jmol+$nmol*$clust_comp[$iclus][$n_corr_positive_mol[$imol]];
				}
				$nmol = $nmol*($n_max_type_pos[$imol]+1);
			}
			if($first_pos > 0){
				$lines{'nof1'} .= ($clust_comp[$iclus][0]+$clust_comp[$iclus][$first_pos]) . ", ";
				$lines{'tp'} .= "\[" . ($clust_comp[$iclus][0]+$clust_comp[$iclus][$first_pos]+1) . " $jmol\] ";
			}else{
				$lines{'nof1'} .= "$clust_comp[$iclus][0], ";
				$lines{'tp'} .= "\[" . ($clust_comp[$iclus][0]+1) . " $jmol\] ";
			}
		}elsif($iclus==$n_generic_neg){
			$lines{'cst'} .= "2, ";
			$lines{'n'} .= "$iclus, ";
			$k += 1;
			$lines{'nof1'} .= "0, ";
		}elsif($iclus==$n_generic_pos){
			$lines{'cst'} .= "3, ";
			$lines{'p'} .= "$iclus, ";
			$l += 1;
			$lines{'nof1'} .= "0, ";
		}
	}
	for($iclus=$max_cluster_number+1;$iclus<=$size_C_out;$iclus++){
        if($iclus > $max_n_flux){
            last;
        }
		$lines{'cl'} .= "'" . $label[$iclus] . "' ";
	}
	#if($include_generic_neg){
	#	$lines{'n'} .= "$n_generic_neg ";
	#	$k += 1;
	#	$lines{'nof1'} .= "0, ";
	#}
	#if($include_generic_pos){
	#	$lines{'p'} .= "$n_generic_pos ";
	#	$l += 1;
	#	$lines{'nof1'} .= "0, ";
	#}
	$ii = 0;
	$kk = 0;
	$ll = 0;
	for($imol=1;$imol<=$nmol_types_used;$imol++){
		for($irule=0;$irule<$n_nucl_rules;$irule++){
			if($ii==15){
				$lines{'out0'} .= "&\n\t\t&";
				$ii = 0;
			}
			$lines{'out0'} .= "$nucl_rules[$irule][$mol_types_used[$imol]], ";
			$ii += 1;
		}
		for($irule=0;$irule<$n_nucl_rules_neg;$irule++){
			if($kk==15){
				$lines{'outn'} .= "&\n\t\t&";
				$kk = 0;
			}
			$lines{'outn'} .= "$nucl_rules_neg[$irule][$mol_types_used[$imol]], ";
			$kk += 1;
		}
		for($irule=0;$irule<$n_nucl_rules_pos;$irule++){
			if($ll==15){
				$lines{'outp'} .= "&\n\t\t&";
				$ll = 0;
			}
			$lines{'outp'} .= "$nucl_rules_pos[$irule][$mol_types_used[$imol]], ";
			$ll += 1;
		}
	}

	$lines{'1of1'} =~ s/, $//;
	$lines{'nof1'} =~ s/, $//;
	$lines{'0'} =~ s/, $//;
	$lines{'n'} =~ s/, $//;
	$lines{'p'} =~ s/, $//;
	$lines{'0m'} =~ s/, $//;
	$lines{'nm'} =~ s/, $//;
	$lines{'pm'} =~ s/, $//;
	$lines{'0c'} =~ s/, $//;
	$lines{'nc'} =~ s/, $//;
	$lines{'pc'} =~ s/, $//;
	$lines{'cst'} =~ s/, $//;
	$lines{'m'} =~ s/, $//;
	$lines{'d'} =~ s/, $//;
	$lines{'dm'} =~ s/, $//;
	$lines{'mon'} =~ s/ $//;
	$lines{'nmon'} =~ s/ $//;
	$lines{'cl'} =~ s/ $//;
	$lines{'t0'} =~ s/ $//;
	$lines{'tn'} =~ s/ $//;
	$lines{'tp'} =~ s/ $//;
	$lines{'out0'} =~ s/, $//;
	$lines{'outn'} =~ s/, $//;
	$lines{'outp'} =~ s/, $//;
	
	if($lines{'out0'} !~ /^\s*$/){
		$lines{'out0'} = "reshape((/$lines{'out0'}/),(/$n_nucl_rules, $nmol_types_used/))";
	}
	if($lines{'outn'} !~ /^\s*$/){
		$lines{'outn'} = "reshape((/$lines{'outn'}/),(/$n_nucl_rules_neg, $nmol_types_used/))";
	}
	if($lines{'outp'} !~ /^\s*$/){
		$lines{'outp'} = "reshape((/$lines{'outp'}/),(/$n_nucl_rules_pos, $nmol_types_used/))";
	}
	
	if($lfortran){
		print SYST "integer, parameter :: n_1$molecule_name[0]_clusters = $i\t\t\t\t! number molecules and clusters containing 1 $molecule_name[0] molecule\n";
		print SYST "\ninteger, parameter :: n_neutrals = $j\t\t\t! number of neutral molecules and clusters\n";
		print SYST "integer, parameter :: n_negatives = $k\t\t\t! negative\n";
		print SYST "integer, parameter :: n_positives = $l\t\t\t! positive\n";
        print SYST "integer, parameter :: nclust_nogen = $max_cluster\t\t\t! number of clusters and molecules excluding generic ions\n";
		print SYST "\ninteger, parameter :: n_neutral_monomers = $jm, neutral_monomers($jm) = (/$lines{'0m'}/)\t\t\t! number and indices of neutral monomers\n";
		print SYST "integer, parameter :: n_negative_monomers = $km";
		if($km>0){
			print SYST ", negative_monomers($km) = (/$lines{'nm'}/)";
		}
		print SYST "\t\t\t! negative\n";
		print SYST "integer, parameter :: n_positive_monomers = $lm";
		if($lm>0){
			print SYST ", positive_monomers($lm) = (/$lines{'pm'}/)";
		}
		print SYST "\t\t\t! positive\n";
		print SYST "\ninteger, parameter :: n_neutral_clusters = $jc\t\t\t! number of neutral clusters\n";
		print SYST "integer, parameter :: n_negative_clusters = $kc\t\t\t! negative\n";
		print SYST "integer, parameter :: n_positive_clusters = $lc\t\t\t! positive\n\n";
	
		$clust_mass_max = sprintf("%.2f",$clust_mass_max);
		$clust_mass_max =~ s/e/d/;
		print SYST "real(kind(1.d0)), parameter :: mass_max = $clust_mass_max\n";
		$diameter_max = sprintf("%.2f",$diameter_max);
		$diameter_max =~ s/e/d/;
		print SYST "real(kind(1.d0)), parameter :: diameter_max = $diameter_max\n";
		$mob_diameter_max = sprintf("%.2f",$mob_diameter_max);
		$mob_diameter_max =~ s/e/d/;
		print SYST "real(kind(1.d0)), parameter :: mob_diameter_max = $mob_diameter_max\n";
		
		# Maximum molecular content by charge (currently not needed)
		# print SYST "integer, parameter :: nmols_max($ncharges, $nmol_types_used) = reshape((/" . join(',',@n_max_type[@mol_types_used[1..$nmol_types_used]]);
		# if($include_negative_ion_terms){
			# print SYST "," . join(',',@n_max_type_neg[@mol_types_used[1..$nmol_types_used]]);
		# }
		# if($include_positive_ion_terms){
			# print SYST "," . join(',',@n_max_type_pos[@mol_types_used[1..$nmol_types_used]]);
		# }
		# print SYST "/),(/$ncharges, $nmol_types_used/))\t\t! maximum molecular content by charge\n";
        
		# Overall maximum molecular content
		print SYST "integer, parameter :: ij_ind_max($nmol_types_used) = (/";
		$str_temp = "";
		for($imol=1;$imol<=$nmol_types_used;$imol++){
			$str_temp .= max($n_max_type[$mol_types_used[$imol]],$n_max_type_neg[$mol_types_used[$imol]],$n_max_type_pos[$mol_types_used[$imol]]) . ", ";
		}
		$str_temp =~ s/, $//;
		print SYST "$str_temp/)\t\t! maximum molecular content\n";
        
        # Clusters that are at the boundary of the system (i.e. at least one component has its maximum molecular number)
        $n_at_bound = 0;
        @clus_at_bound = ();
        for($iclus=1;$iclus<=$max_cluster;$iclus++){
            @temp_array = @{ $clust_comp[$iclus] };
            $lfound = 0;
            for($imol=1;$imol<=$nmol_types_used;$imol++){
                if ($charge[$mol_types_used[$imol]] != 0){
                    next;
                }
                if($lneutral_cluster[$iclus]){
                    if($n_max_type[$mol_types_used[$imol]]==0){
                        next;
                    }elsif($temp_array[$mol_types_used[$imol]]==$n_max_type[$mol_types_used[$imol]]){
                        $lfound = 1;
                        last;
                    }
                }elsif($lnegative_cluster[$iclus]){
                    if($n_max_type_neg[$mol_types_used[$imol]]==0){
                        next;
                    }elsif($temp_array[$mol_types_used[$imol]]==$n_max_type_neg[$mol_types_used[$imol]]){
                        $lfound = 1;
                        last;
                    }
                }elsif($lpositive_cluster[$iclus]){
                    if($n_max_type_pos[$mol_types_used[$imol]]==0){
                        next;
                    }elsif($temp_array[$mol_types_used[$imol]]==$n_max_type_pos[$mol_types_used[$imol]]){
                        $lfound = 1;
                        last;
                    }
                }
            }
            if($lfound){
                $n_at_bound += 1;
                push(@clus_at_bound,$iclus);
            }
        }
        print SYST "integer, parameter :: n_bound = $n_at_bound\t\t! number of clusters at the system boundary\n";
        print SYST "integer, parameter :: n_comp_out = $n_comp_out\t\t! number of clusters growing out in different compositions\n";	

		if($lines{'out0'} !~ /^\s*$/){
			print SYST "\ninteger, parameter :: nmols_out_neutral($n_nucl_rules, $nmol_types_used) = $lines{'out0'}\t\t\t! criteria for outgrowing neutrals\n";
		}
		if($lines{'outn'} !~ /^\s*$/){
			print SYST "integer, parameter :: nmols_out_negative($n_nucl_rules_neg, $nmol_types_used) = $lines{'outn'}\t\t\t! negatives\n";
		}
		if($lines{'outp'} !~ /^\s*$/){
			print SYST "integer, parameter :: nmols_out_positive($n_nucl_rules_pos, $nmol_types_used) = $lines{'outp'}\t\t\t! positives\n";
		}
	
		$lines{'a_inp'} = '';
		$lines{'a_size'} = '';
		$lines{'a_def'} = '';
		$lines{'c_inp'} = '';
		$lines{'c_size'} = '';
		$lines{'c_def'} = '';
		print SYST "\n\ncontains\n\nsubroutine n_$molecule_name[0]_in_clusters$append_to_syst_names(n_$molecule_name[0])\n\timplicit none\n";
		print SYST "\tinteger :: n_$molecule_name[0]($max_cluster_number)\n\n";
		print SYST "\tn_$molecule_name[0] = (/$lines{'nof1'}/)\n\n";
		print SYST "end subroutine n_$molecule_name[0]_in_clusters$append_to_syst_names\n\n";
		print SYST "subroutine clusters_with_1_$molecule_name[0]$append_to_syst_names(cluster_numbers)\n\timplicit none\n";
		print SYST "\tinteger :: cluster_numbers($i)\n\n\tcluster_numbers = (/$lines{'1of1'}/)\n\n";
		print SYST "end subroutine clusters_with_1_$molecule_name[0]$append_to_syst_names\n\n";
		if($j>0 && ($k+$l)>0 && $lines{'0'} ne ''){
			$lines{'a_inp'} .= "neutrals, ";
			$lines{'a_size'} .= "neutrals($j), ";
			$lines{'a_def'} .= "\tneutrals = (/$lines{'0'}/)\n";
		}
		if($lines{'0c'} ne ''){
			$lines{'c_inp'} .= "neutral_clusters, ";
			$lines{'c_size'} .= "neutral_clusters($jc), ";
			$lines{'c_def'} .= "\tneutral_clusters = (/$lines{'0c'}/)\n";
		}
		if($k>0){
			if(($j+$l)>0 && $lines{'n'} ne ''){
				$lines{'a_inp'} .= "negatives, ";
				$lines{'a_size'} .= "negatives($k), ";
				$lines{'a_def'} .= "\tnegatives = (/$lines{'n'}/)\n";
			}
			if($lines{'nc'} ne ''){
				$lines{'c_inp'} .= "negative_clusters, ";
				$lines{'c_size'} .= "negative_clusters($kc), ";
				$lines{'c_def'} .= "\tnegative_clusters = (/$lines{'nc'}/)\n";
			}
		}
		if($l>0){
			if(($j+$k)>0 && $lines{'p'} ne ''){
				$lines{'a_inp'} .= "positives, ";
				$lines{'a_size'} .= "positives($l), ";
				$lines{'a_def'} .= "\tpositives = (/$lines{'p'}/)\n";
			}
			if($lines{'pc'} ne ''){
				$lines{'c_inp'} .= "positive_clusters, ";
				$lines{'c_size'} .= "positive_clusters($lc), ";
				$lines{'c_def'} .= "\tpositive_clusters = (/$lines{'pc'}/)\n";
			}
		}
		$lines{'a_inp'} =~ s/, $//;
		if($lines{'a_inp'} ne ''){
			print SYST "subroutine arrays$append_to_syst_names($lines{'a_inp'})\n\timplicit none\n";
			$lines{'a_size'} =~ s/, $//;
			print SYST "\tinteger :: $lines{'a_size'}\n\n";
			print SYST $lines{'a_def'};
			print SYST "\nend subroutine arrays$append_to_syst_names\n\n";
		}
		$lines{'c_inp'} =~ s/, $//;
		print SYST "subroutine cluster_arrays$append_to_syst_names($lines{'c_inp'})\n\timplicit none\n";
		$lines{'c_size'} =~ s/, $//;
		print SYST "\tinteger :: $lines{'c_size'}\n\n";
		print SYST $lines{'c_def'};
		print SYST "\nend subroutine cluster_arrays$append_to_syst_names\n\n";
		

		print SYST "subroutine get_charging_state$append_to_syst_names(charging_state)\n\timplicit none\n";
		print SYST "\tinteger :: charging_state($max_cluster_number)\n\n\tcharging_state = (/$lines{'cst'}/)\n";
		print SYST "\nend subroutine get_charging_state$append_to_syst_names\n\n";

	
		print SYST "subroutine get_mass$append_to_syst_names(mass)\n\timplicit none\n";
		print SYST "\treal(kind(1.d0)) :: mass($max_cluster_number)\n\n\tmass = (/$lines{'m'}/)\n";
		print SYST "\nend subroutine get_mass$append_to_syst_names\n\n";
	
	
		print SYST "subroutine get_diameter$append_to_syst_names(diameter)\n\timplicit none\n\n";
		print SYST "\treal(kind(1.d0)) :: diameter($max_cluster_number)\n\n\t diameter = (/$lines{'d'}/)\t! dry value\n";
		print SYST "\nend subroutine get_diameter$append_to_syst_names\n\n";
	
	
		print SYST "subroutine get_mob_diameter$append_to_syst_names(mob_diameter)\n\timplicit none\n\n";
		print SYST "\treal(kind(1.d0)) :: mob_diameter($max_cluster_number)\n\n\t mob_diameter = (/$lines{'dm'}/)\t! dry value\n";
		print SYST "\nend subroutine get_mob_diameter$append_to_syst_names\n\n";
	
		print SYST "subroutine cluster_names$append_to_syst_names(clust)\n\timplicit none\n\tcharacter(len=11), dimension(".min($size_C_out,$max_n_flux).") :: clust\n";
        print SYST "\n";
		for($iclus=1;$iclus <= $size_C_out;$iclus++){
            if($iclus > $max_n_flux){
                last;
            }
			if($lhydrate_average && $lhas_hydr[$iclus]==1){
				$line = "\t! $hydrates_str[$iclus]";
			}else{
				$line = '';
			}
			print SYST "\tclust($iclus)(:) = '$label[$iclus]'$line\n";
		}
        if($l_save_coag_per_clust || $l_save_outgoing_clust){
            print SYST "\n\t! Additional flux elements not listed here:\n";
            if($l_save_coag_per_clust){
                print SYST "\t! Elements from $range_coag_per_clust[0] to $range_coag_per_clust[1]: coagulation loss of each cluster\n";
            }
            if($l_save_outgoing_clust){
                print SYST "\t! Elements from $range_out_clust[0] to $range_out_clust[1]: each outgrown cluster composition\n";
            }
        }
		print SYST "\nend subroutine cluster_names$append_to_syst_names\n\n";

	}else{

		# print the cluster names and some info on the clusters

		print DRIVER "\n\n% Cluster definitions etc.\n\n";

		$lines{'nof1'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'0'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'n'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'p'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'0c'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'nc'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'pc'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'cst'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'m'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'d'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'dm'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'out0'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'outn'} =~ s/&\n\t\t&/...\n\t\t/g;
		$lines{'outp'} =~ s/&\n\t\t&/...\n\t\t/g;
	
		$lines{'nof1'} =~ s/, / /g;
		$lines{'0'} =~ s/, / /g;
		$lines{'n'} =~ s/, / /g;
		$lines{'p'} =~ s/, / /g;
		$lines{'0m'} =~ s/, / /g;
		$lines{'nm'} =~ s/, / /g;
		$lines{'pm'} =~ s/, / /g;
		$lines{'0c'} =~ s/, / /g;
		$lines{'nc'} =~ s/, / /g;
		$lines{'pc'} =~ s/, / /g;
		$lines{'cst'} =~ s/, / /g;
		$lines{'m'} =~ s/, / /g;
		$lines{'d'} =~ s/, / /g;
		$lines{'dm'} =~ s/, / /g;
		$lines{'out0'} =~ s/, / /g;
		$lines{'outn'} =~ s/, / /g;
		$lines{'outp'} =~ s/, / /g;
		
		$line = "\t% molecule names\n\tlabels = {";
		$line2 = "\t% neutral, negative and positive species\n\tlabels_ch = {";
		for($imol=1;$imol<=$nmol_types_used;$imol++){
			$line = $line . "'" . $mol_names_used[$imol] . "' ";
			$jmol = $mol_types_used[$imol];
			if($charge[$jmol] == 0){
				$line2 = $line2 . "'" . $molecule_name[$jmol] . "' ";
				if($n_corr_negative_mol[$jmol] ~~ @mol_types_used){
					$line2 = $line2 . "'" . $corr_negative_mol[$jmol] . "' ";
				}elsif($missing_proton ~~ @mol_types_used && &compare_clusters($corr_negative_mol[$jmol],"1$molecule_name[$jmol]1$label_missing_proton")){
					$line2 = $line2 . "'" . $label_missing_proton . "' ";
				}else{
					$line2 = $line2 . "'' ";
				}
				if($n_corr_positive_mol[$jmol] ~~ @mol_types_used){
					$line2 = $line2 . "'" . $corr_positive_mol[$jmol] . "' ";
				}elsif($proton ~~ @mol_types_used && &compare_clusters($corr_positive_mol[$jmol],"1$molecule_name[$jmol]1$label_proton")){
					$line2 = $line2 . "'" . $label_proton . "' ";
				}else{
					$line2 = $line2 . "'' ";
				}
				$line2 = $line2 . "; ";
			}elsif($jmol != $proton && $jmol != $missing_proton && !($n_corr_neutral_mol[$jmol] ~~ @mol_types_used)){
				if($charge[$jmol] == -1){
					$line2 = $line2 . "'' '" . $molecule_name[$jmol] . "' ''";
				}elsif($charge[$jmol] == 1){
					$line2 = $line2 . "'' '' '" . $molecule_name[$jmol] . "'";
				}
				$line2 = $line2 . "; ";
			}
		}
		$line =~ s/ $//;
		$line = "$line};\n";
		print DRIVER $line;
		# "Cluster-phase ions", i.e. missing or extra protons
		$line2 = $line2 . "'' ";
		if($missing_proton ~~ @mol_types_used){
			$line2 = $line2 . "'" . $label_missing_proton . "' ";
		}else{
			$line2 = $line2 . "'' ";
		}
		if($proton ~~ @mol_types_used){
			$line2 = $line2 . "'" . $label_proton . "' ";
		}else{
			$line2 = $line2 . "'' ";
		}
		$line2 = $line2 . "; ";
		# "Gas-phase ions", i.e. generic charger ions
		$line2 = $line2 . "'' ";
		if($include_generic_neg){
			$line2 = $line2 . "'" . $label_generic_neg . "' ";
		}else{
			$line2 = $line2 . "'' ";
		}
		if($include_generic_pos){
			$line2 = $line2 . "'" . $label_generic_pos . "' ";
		}else{
			$line2 = $line2 . "'' ";
		}
		$line2 =~ s/ $//;
		$line2 = "$line2};\n";
		print DRIVER $line2;
		
		print DRIVER "\t% cluster names\n\tclust = {$lines{'cl'}};\n";
		# print out also the cluster names plus the names of the other fluxes (sources, losses etc.)
		$line = "\t% name vector containing also the names of fluxes other than clusters (sources, losses etc.)\n\tclust_flux = [clust ";
		for($iclus=$max_cluster_number+1;$iclus<=$max_n_flux_inc_boundary_clusters;$iclus++){
			$line = $line . "'" . $label_inc_boundary_clusters[$iclus] . "' ";
		}
		$line =~ s/ $//;
		$line = "$line];\n";
		print DRIVER $line;
		
		print DRIVER "\tcharging_states = [$lines{'cst'}]; % charging states (1 = neutral, 2 = negative, 3 = positive)\n";
		print DRIVER "\t% dry values\n\tdiameters = [$lines{'d'}];\n";
		print DRIVER "\t% dry values\n\tmobility_diameters = [$lines{'dm'}]; % mobility diameter (2*r+0.3nm)*sqrt(1+28.8u/m)\n";
		print DRIVER "\tmasses = [$lines{'m'}]; % mass in amus\n";
		print DRIVER "\tmonomers = [$lines{'mon'}];\n";
		print DRIVER "\tnonmonomers = [$lines{'nmon'}];\n";
		print DRIVER "\tneutrals = [$lines{'0'}];\n";
		print DRIVER "\tnegatives = [$lines{'n'}];\n";
		print DRIVER "\tpositives = [$lines{'p'}];\n";
		print DRIVER "\tneutral_monomers = [$lines{'0m'}];\n";
		print DRIVER "\tnegative_monomers = [$lines{'nm'}];\n";
		print DRIVER "\tpositive_monomers = [$lines{'pm'}];\n";
		print DRIVER "\tneutral_clusters = [$lines{'0c'}];\n";
		print DRIVER "\tnegative_clusters = [$lines{'nc'}];\n";
		print DRIVER "\tpositive_clusters = [$lines{'pc'}];\n";
		print DRIVER "\t" . $molecule_name[0] . "_in_clust = [$lines{'nof1'}];\n";
		print DRIVER "\ttable_0 = {$lines{'t0'}};\n";
		print DRIVER "\ttable_neg = {$lines{'tn'}};\n";
		print DRIVER "\ttable_pos = {$lines{'tp'}};\n";
		
		if($lines{'out0'} !~ /^\s*$/){
			$lines{'out0'} =~ s/\(\//\[/g;
			$lines{'out0'} =~ s/\/\)/\]/g;
			print DRIVER "\t% criteria for outgrowing neutrals\n\tnmols_out_neutral = $lines{'out0'};\n";
		}
		if($lines{'outn'} !~ /^\s*$/){
			$lines{'outn'} =~ s/\(\//\[/g;
			$lines{'outn'} =~ s/\/\)/\]/g;
			print DRIVER "\t% criteria for outgrowing negatives\n\tnmols_out_negative = $lines{'outn'};\n";
		}
		if($lines{'outp'} !~ /^\s*$/){
			$lines{'outp'} =~ s/\(\//\[/g;
			$lines{'outp'} =~ s/\/\)/\]/g;
			print DRIVER "\t% criteria for outgrowing positives\n\tnmols_out_positive = $lines{'outp'};\n";
		}
		
	}
}else{

	print SYST "integer, parameter :: ij_ind_max($nmol_types_used) = (/$nmol_ranges_list/)\n";
	if($nmol_types_used>1 && $lloop_cs){
		print SYST "integer, parameter :: ij_ind_cs($nmol_types_used) = (/$nmol_cs_list/)\n";
	}

	$str_temp = '';
	for($imol=1;$imol<=$nmol_types_used;$imol++){
		$str_temp .= "$n_max_type[$mol_types_used[$imol]]$mol_names_used[$imol]";
	}
	($string1,$string2) = &determine_cluster_composition($str_temp);
	@temp_array=@$string1;
	$diameter_max = &calculate_radius(\@temp_array)*2e9;
	$diameter_max = sprintf("%.2f",$diameter_max);
	$diameter_max =~ s/e/d/;
	print SYST "real(kind(1.d0)), parameter :: diameter_max = $diameter_max\n";

	print SYST "\ncontains\n\n";
}

if($lfortran){
	print SYST "subroutine monomer_names$append_to_syst_names(clust_mon)\n\timplicit none\n";
	print SYST "\tcharacter(len=11), dimension($nmolecules) :: clust_mon\n\n";
	for($imol=1;$imol<=$nmolecules;$imol++){
		if(!$lloop){
			$str_temp = $label[$molecules[$imol]];
		}else{
			$str_temp = "1".$mol_names_used[$imol]; # loop mode: no charged components, for now
		}
		print SYST "\tclust_mon($imol)(:) = '$str_temp'\n";
	}
	print SYST "\nend subroutine monomer_names$append_to_syst_names\n\n";

	print SYST "subroutine molecule_names$append_to_syst_names(labels)\n\timplicit none\n";
	print SYST "\tcharacter(len=11), dimension($nmol_types_used) :: labels\n\n";
	for($imol=1;$imol<=$nmol_types_used;$imol++){
		print SYST "\tlabels($imol)(:) = '$mol_names_used[$imol]'\n";
	}
	print SYST "\nend subroutine molecule_names$append_to_syst_names\n\n";
	
	print SYST "subroutine monomer_indices$append_to_syst_names(n_monomers)\n\timplicit none\n";
	print SYST "\tinteger :: n_monomers($nmolecules)\n";
	if($lloop && $nmol_types_used>1){
		print SYST "\tinteger :: clust_from_indices($nmol_comp_list), i, ij_ind($nmol_types_used)\n\n";
        # This may be inconsistent if the equations and system files have different subroutine suffices - but
        # such setting doesn't sound very likely for the loop mode, so just print out a warning and deal with this if need be
        if($append_to_eq_names ne $append_to_syst_names){
            print "Warning: calling a subroutine with suffix \"$append_to_eq_names\" in file $system_file_name_fortran which contains subroutines with suffix \"$append_to_syst_names\".\n";
        }
		print SYST "\tcall get_cluster_numbers$append_to_eq_names(clust_from_indices)\n";
		print SYST "\tn_monomers = 0\n\n";
		print SYST "\tdo i = 1,$nmol_types_used\n";
		print SYST "\t\tij_ind = 0\n";
		print SYST "\t\tij_ind(i) = 1\n";
		print SYST "\t\tn_monomers(i) = clust_from_indices($nmol_ranges_ij_ind)\n";
		print SYST "\tend do\n\n";
	}else{
		print SYST "\n\tn_monomers = (/$monomer_indices/)\n\n";
	}
	print SYST "end subroutine monomer_indices$append_to_syst_names\n\n";
    
    if(!$lloop){
        # Compositions and indices of clusters at the system boundary
        print SYST "subroutine get_bound$append_to_syst_names(bound_clusters,nmols_bound)\n\timplicit none\n";
        print SYST "\tinteger :: bound_clusters($n_at_bound), nmols_bound($n_at_bound,$nmol_types_used)\n\n";
        $str_temp = "\tbound_clusters = (/";
        for($i=0;$i<$n_at_bound;$i++){
            $iclus = $clus_at_bound[$i];
            print SYST "\tnmols_bound(" . ($i+1) . ",:) = (/" . join(', ',@{ $clust_comp[$iclus] }[@mol_types_used[1..$nmol_types_used]]) . "/)\n";
            $str_temp .= "$iclus, ";
		}
        $str_temp =~ s/, $//;
        print SYST "\n" . $str_temp . "/)\n\n";
        print SYST "end subroutine get_bound$append_to_syst_names\n\n";
        
        # Diameters and compositions of individual clusters growing out of the system
        print SYST "subroutine get_diameter_out$append_to_syst_names(diameter_out)\n\timplicit none\n";
        print SYST "\treal(kind(1.d0)) :: diameter_out($n_comp_out)\n\n";
        $lines{'d'} = "";	# Mass diameters of the ougrowing clusters
        $jclus = 0;
        for($iclus=1;$iclus<=$n_comp_out;$iclus++){
            if($jclus==10){
                $lines{'d'} .= "&\n\t\t&";
                $jclus = 0;
            }
            $jclus += 1;
            $diameter = sprintf("%.2f",&calculate_radius(\@{ $clust_comp_out[$iclus] })*2e9);
            $diameter =~ s/e/d/;
            $lines{'d'} .= "$diameter, ";
        }
        $lines{'d'} =~ s/, $//;
        print SYST "\tdiameter_out = (/$lines{'d'}/)\t! dry value\n\n";
        print SYST "end subroutine get_diameter_out$append_to_syst_names\n\n";
        
        print SYST "subroutine get_nmols_out$append_to_syst_names(nmols_out)\n\timplicit none\n";
        print SYST "\tinteger :: nmols_out($n_comp_out,$nmol_types_used)\n\n";
        for($iclus=1;$iclus<=$n_comp_out;$iclus++){
            print SYST "\tnmols_out($iclus,:) = (/" . join(', ',@{ $clust_comp_out[$iclus] }[@mol_types_used[1..$nmol_types_used]]) . "/)\n";
        }
        print SYST "\n";
        print SYST "end subroutine get_nmols_out$append_to_syst_names\n\n";
        
        # Cluster composition as neutral molecules, i.e. charged molecules are counted as their neutral counterparts
        print SYST "subroutine molecule_names_nocharge$append_to_syst_names(labels_nocharge)\n\timplicit none\n";
        print SYST "\tcharacter(len=11), dimension($jm) :: labels_nocharge\n\n";
        $i = 0;
        for($imol=1;$imol<=$nmol_types_used;$imol++){
            if($charge[$mol_types_used[$imol]] == 0){
                $i += 1;
                print SYST "\tlabels_nocharge($i)(:) = '$molecule_name[$mol_types_used[$imol]]'\n";
            }
        }
        print SYST "\nend subroutine molecule_names_nocharge$append_to_syst_names\n\n";
        # Get the neutral-equivalent composition for both the simulated and the outgrown clusters
        for($ii=0;$ii<=1;$ii++){
            if($ii == 0){
                # Simulated clusters
                $str_temp = "";
                $str_temp2 = "_clust";
                $temp_val = $max_cluster_number;
                $temp_val2 = $max_cluster;
            }else{
                # Outgrown clusters
                $str_temp = "_out";
                $str_temp2 = "_out";
                $temp_val = $n_comp_out;
                $temp_val2 = $n_comp_out;
            }
            print SYST "subroutine get_nmols_nocharge$str_temp$append_to_syst_names(nmols_nocharge$str_temp2)\n\timplicit none\n";
            print SYST "\tinteger :: nmols_nocharge$str_temp2($temp_val,$jm)\n\n";
            print SYST "\tnmols_nocharge$str_temp2 = 0\n\n";
            for($iclus=1;$iclus <= $temp_val2;$iclus++){
                @temp_array = (0) x $jm;
                if($ii == 0){
                    @temp_array_2 = @{ $clust_comp[$iclus] };
                }else{
                    @temp_array_2 = @{ $clust_comp_out[$iclus] };
                }
                $i = -1;
                for($imol=1;$imol<=$nmol_types_used;$imol++){
                    if($charge[$mol_types_used[$imol]] == 0){
                        $i += 1;
                        $temp_array[$i] += $temp_array_2[$mol_types_used[$imol]];
                        if($n_corr_negative_mol[$mol_types_used[$imol]] >= 0){
                            $temp_array[$i] += $temp_array_2[$n_corr_negative_mol[$mol_types_used[$imol]]];
                        }
                        if($n_corr_positive_mol[$mol_types_used[$imol]] >= 0){
                            $temp_array[$i] += $temp_array_2[$n_corr_positive_mol[$mol_types_used[$imol]]];
                        }
                    }
                }
                print SYST "\tnmols_nocharge$str_temp2($iclus,:) = (/" . join(', ',@temp_array) . "/)\n";
            }
            print SYST "\n";
            print SYST "end subroutine get_nmols_nocharge$str_temp$append_to_syst_names\n\n";
        }
    }
    
	print SYST "\nend module acdc_system$append_to_syst_names\n\n";
	close(SYST);
}

################################################################################
################################################################################
##      8.2 dC/dt for Fortran                                                 ##
################################################################################
################################################################################

if($lfortran){
	# Opening the Fortran output file
	open(OUT, ">$output_file_name_fortran") || die "\nCould not open output file $output_file_name_fortran\n\n";
	
	if($lloop){
		print OUT "!!!!!!!!!!!!!!!!!!!!!!!! KEY !!!!!!!!!!!!!!!!!!!!!!!!\n!\n";
		if($nmol_types_used==1){
			print OUT "! $max_cluster clusters with 1-$n_max_type[$mol_types_used[1]] $molecule_name[$mol_types_used[1]] molecules\n";
		}else{
			if($lloop_restrict){
				print OUT "! Cluster set will be restricted according to the criteria given by the user\n";
				print OUT "! Available clusters from which the set is selected:\n";
			}
			print OUT "! $max_cluster clusters with\n";
			for($imol=0;$imol<$nmol_types;$imol++){
				if($n_max_type[$imol]>0){
					print OUT "!   0-$n_max_type[$imol] $molecule_name[$imol] molecules\n";
				}
			}
			if($l_save_outgoing){
				print OUT "! and the last element is the outgoing flux\n";
			}
		}
		if($l_j_in){
			print OUT "!\n! using a source for cluster n_j_in and omitting the distribution below it\n";
		}
		print OUT "!\n!!!!!!!!!!!!!!!!!!!!!! END KEY !!!!!!!!!!!!!!!!!!!!!!\n\n";
	}else{
		print OUT "!!!!!!!!!!!!!!!!!!!!!!!! KEY !!!!!!!!!!!!!!!!!!!!!!!!\n";
		for($iclus=1;$iclus<=$max_n_flux;$iclus++){
			$line = $comments[$iclus];
			$line =~ s/%/!/;
			print OUT "$line\n";
		}
        if($l_save_coag_per_clust){
            print OUT "! $range_coag_per_clust[0]-$range_coag_per_clust[1] are for coagulation losses of each cluster\n";
        }
        if($l_save_outgoing_clust){
            print OUT "! $range_out_clust[0]-$range_out_clust[1] are for collisions that lead out of the system to different cluster compositions\n";
        }
		print OUT "!!!!!!!!!!!!!!!!!!!!!! END KEY !!!!!!!!!!!!!!!!!!!!!!\n\n";
		
		#maximum number of columns in the index tables
		$ind_quad_loss[0] = 0;
		$ind_quad_form[0] = 0;
		$ind_quad_loss_extra[0] = 0;
		$ind_quad_form_extra[0] = 0;
		$ind_lin_loss[0] = 0;
		$ind_lin_form[0] = 0;
		$ind_reac_loss[0] = 0;
		$ind_reac_form[0] = 0;
		for($iclus=1;$iclus <= $max_n_flux;$iclus++){
			if($ind_quad_loss[$iclus][0]*2>$ind_quad_loss[0]){
				$ind_quad_loss[0]=$ind_quad_loss[$iclus][0]*2;
			}
			if($ind_quad_form[$iclus][0]*2>$ind_quad_form[0]){
				$ind_quad_form[0]=$ind_quad_form[$iclus][0]*2;
			}
			if($ind_quad_loss_extra[$iclus][0]*3>$ind_quad_loss_extra[0]){
				$ind_quad_loss_extra[0]=$ind_quad_loss_extra[$iclus][0]*3;
			}
			if($ind_quad_form_extra[$iclus][0]*3>$ind_quad_form_extra[0]){
				$ind_quad_form_extra[0]=$ind_quad_form_extra[$iclus][0]*3;
			}
			if($ind_lin_loss[$iclus][0]*2>$ind_lin_loss[0]){
				$ind_lin_loss[0]=$ind_lin_loss[$iclus][0]*2;
			}
			if($ind_lin_form[$iclus][0]*2>$ind_lin_form[0]){
				$ind_lin_form[0]=$ind_lin_form[$iclus][0]*2;
			}
			if($ind_reac_loss[$iclus][0]*2>$ind_reac_loss[0]){
				$ind_reac_loss[0]=$ind_reac_loss[$iclus][0]*2;
			}
			if($ind_reac_form[$iclus][0]*2>$ind_reac_form[0]){
				$ind_reac_form[0]=$ind_reac_form[$iclus][0]*2;
			}
		}
	}
	
	print OUT "! differential equations: f = dc/dt\n";
	if($lloop && !$lloop_cs && !$l_save_outgoing){
		print OUT "subroutine feval$append_to_eq_names(neqn,t,c,f_out,coef,ipar)\n";
	}else{
		print OUT "subroutine feval$append_to_eq_names(neqn,t,c,f,coef,ipar)\n";
	}
	if($lloop){
		if($nmol_types_used>1){
			print OUT "use acdc_system$append_to_syst_names, only : monomer_indices$append_to_syst_names\n";
		}
		print OUT "use acdc_simulation_setup$append_to_ext_names, only : sources_and_constants$append_to_ext_names\n";
		if($l_j_in){
			print OUT "use shared_input, only : r_j_in => rlim_for_J";
			print "\nUsing module shared_input in the feval subroutine to get r_j_in\n";
			if($lloop_j_tests){
				print OUT ", r_j_init => rlim_for_J_init\n";
				print OUT "use shared_input, only : use_jtable, use_KK";
			}
			print OUT "\n";
		}
	}
	print OUT "\timplicit none\n";
	print OUT "\tinteger, parameter :: nclust = $max_cluster_number";
	if($lloop_cs){
		if($nmol_types_used==1){
			print OUT ", n_cs = $max_cluster_number";
		}else{
			print OUT ", ij_ind_cs($nmol_types_used) = (/$nmol_cs_list/)";
		}
	}
	print OUT "\n";
	
	if(!$lloop){
		print OUT "\tinteger :: neqn, ipar(4), i, j, k, n\n";
	}else{
		print OUT "\tinteger :: neqn, ipar(4), i, j, ij, n";
		if($nmol_types_used>1){
			print OUT ", ij_ind($nmol_types_used), imol";
		}
		print OUT "\n";
	}
	if($l_j_in){
		print OUT "\tinteger, save :: n_j_in = 0";
		if($lloop_j_tests){
			print OUT ", n_j_init = 0";
		}
		print OUT "\n";
	}
	if($lloop && !$lloop_cs && !$l_save_outgoing){
		print OUT "\treal(kind(1.d0)) :: t, c(neqn), f_out(neqn), f(neqn+1)";
	}else{
		print OUT "\treal(kind(1.d0)) :: t, c(neqn), f(neqn)";
	}
	if($l_mcmc_any){
		print OUT ", coef(" . ($n_mcmc_coefs+$variable_cs+2*$variable_ion_source) . ")";
	}elsif($l_variable_parameters){
		print OUT ", coef($n_variable_parameters)";
	}elsif($lloop && $nmol_types_used>1){
		print OUT ", coef($nmol_types_used)";
	}elsif($lloop){
		print OUT ", coef";
		if($lloop_j_tests || $lgrowth_for_j_tests || $l_j_in){
			print OUT ", m, r";
			if($lloop_j_tests && $l_j_in){
				print OUT ", cs_for_table, gr,coags, j_temp";
			}
		}
	}else{
		print OUT ", coef(:)";
	}
	print OUT "\n";
	if($lloop){
		if($lloop_restrict){
			print OUT "\tlogical, save, allocatable :: isconst(:)\n";
			print OUT "\treal(kind(1.d0)), save, allocatable :: K(:,:)";
			if(!$disable_evap){
				print OUT ", E(:,:)";
			}
			if($l_use_get_losses){
				print OUT ", loss(:)";
			}
			print OUT ", source(:)\n";
			print OUT "\tinteger, save, allocatable :: fitted(:,:)\n";
		}else{
			print OUT "\tlogical, save :: isconst($max_cluster_number) = .false.\n";
			print OUT "\treal(kind(1.d0)), save :: K(nclust,nclust)";
			if(!$disable_evap){
				print OUT ", E(nclust,";
				if($disable_nonmonomer_evaps && $nmol_types_used==1){
					print OUT "1)";
				}else{
					print OUT "nclust)";
				}
			}
			if($l_use_get_losses){
				print OUT ", loss(nclust)";
			}
			print OUT ", source($max_cluster_number)\n";
			print OUT "\tinteger, save :: fitted($max_cluster_number,0:$max_cluster_number)=0\n";
		}
		if($nmol_types_used>1){
			print OUT "\tinteger, save :: nclust_inc=0, indices(nclust,$nmol_types_used)";
			print OUT ", clust_from_indices($nmol_comp_list)";
			print OUT ", n_monomers($nmol_types_used)\n";
		}
	}else{
		print OUT "\tlogical, save :: isconst($size_C_eqn) = .false.\n";
		print OUT "\treal(kind(1.d0)), save :: coef_quad(nclust,nclust,$size_ind_coef)=0.d0,coef_lin($size_ind_coef,$size_ind_coef,nclust)=0.d0,source($size_C_eqn)=0.d0\n";
		print OUT "\tinteger, save :: ind_quad_loss($size_ind_coef,0:$ind_quad_loss[0])=0,ind_quad_form($size_ind_coef,0:$ind_quad_form[0])=0\n";
		print OUT "\tinteger, save :: ind_quad_loss_extra($size_ind_coef,0:$ind_quad_loss_extra[0])=0,ind_quad_form_extra($size_ind_coef,0:$ind_quad_form_extra[0])=0\n";
		print OUT "\tinteger, save :: ind_lin_loss($size_ind_coef,0:$ind_lin_loss[0])=0,ind_lin_form($size_ind_coef,0:$ind_lin_form[0])=0,fitted($size_C_eqn,0:$size_C_eqn)=0\n";
        if($l_save_outgoing_clust){
            print OUT "\tinteger, save :: ind_out_clust(nclust,nclust)=0\n";
        }
		if($l_reac_in_clus){
			print OUT "\tinteger, save :: ind_reac_loss($size_ind_coef,0:$ind_reac_loss[0])=0,ind_reac_form($size_ind_coef,0:$ind_reac_form[0])=0\n";
		}
		print OUT "\treal(kind(1.d0)), save :: n_quad_form_extra($size_ind_coef,0:" . ($ind_quad_form_extra[0])/3 . ")=0.d0\n";
	}
	print OUT $lines{'source_def'};
	print OUT "\treal(kind(1.d0)), parameter :: pi=4.d0*atan(1.d0)\n";
	if($lloop && ($nmol_types_used>1 || $l_j_in)){
		print OUT "\n\t! system size parameters\n";
		if($nmol_types_used>1){
			print OUT "\tif (nclust_inc .eq. 0) then\n";
			print OUT "\t\tcall get_molecule_numbers$append_to_eq_names(nclust_inc,indices)\n";
			print OUT "\t\tcall get_cluster_numbers$append_to_eq_names(clust_from_indices)\n";
			print OUT "\t\tcall monomer_indices$append_to_syst_names(n_monomers)\n";
			if($lloop_restrict){
				print OUT "\t\tallocate(isconst(nclust_inc))\n";
				print OUT "\t\tallocate(fitted(nclust_inc,0:nclust_inc))\n";
				print OUT "\t\tallocate(K(nclust_inc,nclust_inc))\n";
				if(!$disable_evap){
					print OUT "\t\tallocate(E(nclust_inc,nclust_inc))\n";
				}
				if($l_use_get_losses){
					print OUT "\t\tallocate(loss(nclust_inc))\n";
				}
				print OUT "\t\tallocate(source(nclust_inc))\n";
			}
			print OUT "\tend if\n";
		}
		if($l_j_in){
			print OUT "\tif (n_j_in .eq. 0) then\n";
			print OUT "\t\tdo i = 1,nclust\n";
			print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(m,r,i)\n";
			print OUT "\t\t\tif (r*1.d9 .ge. r_j_in) then\n";
			print OUT "\t\t\t\tn_j_in = i\n";
			print OUT "\t\t\t\twrite(*,*) 'Size for which the input J will be used:'\n";
			print OUT "\t\t\t\twrite(*,*) r_j_in,' nm, ',n_j_in,' molecules'\n";
			print OUT "\t\t\t\texit\n";
			print OUT "\t\t\tend if\n";
			print OUT "\t\tend do\n";
			if($lloop_j_tests){
				print OUT "\t\tif (use_KK) then\n";
				print OUT "\t\t\tdo i = 1,nclust\n";
				print OUT "\t\t\t\tcall get_masses_and_radii$append_to_eq_names(m,r,i)\n";
				print OUT "\t\t\t\tif (r*1.d9 .ge. r_j_init) then\n";
				print OUT "\t\t\t\t\tn_j_init = i\n";
				print OUT "\t\t\t\t\twrite(*,*) 'Size from which the input J will be extrapolated:'\n";
				print OUT "\t\t\t\t\twrite(*,*) r_j_init,' nm, ',n_j_init,' molecules'\n";
				print OUT "\t\t\t\t\texit\n";
				print OUT "\t\t\t\tend if\n";
				print OUT "\t\t\tend do\n";
				print OUT "\t\tend if\n";
			}
			print OUT "\tend if\n";
		}
	}
	print OUT "\n\t! these parameters are read at the very beginning and eg. if source terms or collision rates have changed\n";
	print OUT "\tif (ipar(1) .eq. 0) then\n";
	print OUT "\t\t! after this the same values are used until some other routine tells otherwise\n\t\tipar(1) = 1\n";
	if($lloop){
		print OUT "\t\tcall sources_and_constants$append_to_ext_names($nclust_included,source,isconst,fitted)\n";
		if($l_mcmc_any){
			print OUT "\t\tcall get_coll$append_to_eq_names($nclust_included,K,coef)\n";
		}elsif( $variable_temp){
			print OUT "\t\tcall get_coll$append_to_eq_names($nclust_included,K,coef(1))\n";
		}else{
			print OUT "\t\tcall get_coll$append_to_eq_names($nclust_included,K)\n";
		}
		if(!$disable_evap){
			if($l_mcmc_any){
				print OUT "\t\tcall get_evap$append_to_eq_names($nclust_included,E,coef)\n";
			}elsif($variable_temp){
				print OUT "\t\tcall get_evap$append_to_eq_names($nclust_included,E,K,coef(1))\n";
			}else{
				print OUT "\t\tcall get_evap$append_to_eq_names($nclust_included,E)\n";
			}
		}
		# Add the factor that deals with the permutations for processes involving two similar clusters
		# (For speed, it's added here instead of inside the loop)
		if($disable_nonmonomers && $nmol_types_used>1){
			# If only monomer processes are included, add the factor to all monomer-monomer processes,
			# as processes between different types of monomers will be otherwise counted twice in the loop
			print OUT "\t\tdo i = 1,$nmol_types_used\n";
			print OUT "\t\t\tdo j = 1,$nmol_types_used\n";
			print OUT "\t\t\t\tK(n_monomers(i),n_monomers(j)) = 0.5d0*K(n_monomers(i),n_monomers(j))\n";
			print OUT "\t\t\t\tK(n_monomers(j),n_monomers(i)) = K(n_monomers(i),n_monomers(j))\n";
			print OUT "\t\t\tend do\n";
			print OUT "\t\tend do\n";
		}else{
			print OUT "\t\tdo i = 1,$nclust_included\n";
			print OUT "\t\t\tK(i,i) = 0.5d0*K(i,i)\n";
			print OUT "\t\tend do\n";
		}
		if($l_use_get_losses){
			print OUT "\t\tcall get_losses$append_to_eq_names($nclust_included,loss";
			if($variable_cs){
				print OUT ",coef";
			}
			print OUT ")\n";
		}
	}else{
		print OUT "\t\tcall initialize_parameters$append_to_eq_names(coef_quad,coef_lin,ind_quad_loss,ind_quad_form,&\n\t\t&\tind_lin_loss,ind_lin_form,ind_quad_loss_extra,ind_quad_form_extra,&\n";
        if($l_save_outgoing_clust){
            print OUT "\t\t&\tind_out_clust,&\n";
        }
        print OUT "\t\t&\tsource,isconst,fitted";
		if($l_mcmc_any || $l_variable_parameters){
			print OUT ",coef";
		}
		print OUT ",ipar)\n";
		if($ind_quad_form_extra[0]>0){
			print OUT "\t\tn_quad_form_extra(:,1:" . ($ind_quad_form_extra[0]/3) . ") = real(ind_quad_form_extra(:,3:$ind_quad_form_extra[0]:3),kind=kind(1.d0))\n";
		}
	}
	print OUT "\tend if\n\n";
	if($lloop && !$l_variable_parameters){
		print OUT "\t! override the monomer sources given by the subroutine call\n";
		print OUT "\tsource($monomer_indices) = coef\n\n";
	}
	print OUT $lines{'source'};
    print OUT "\t! override the isconst settings, if needed\n";
	print OUT "\tif (ipar(4) .eq. 1) then\n\t\tisconst = .false.\n\tend if\n\n";
	if($lloop){
		print OUT "\tf = 0.d0\n\n";
		if($l_j_in){
			# Assume that the formation at size n_j_in directly reduces the vapor concentration,
			# as is usually done in growth models
			print OUT "\tf(1) = f(1)-n_j_in*source(n_j_in)\n\n";
		}
		if($disable_nonmonomers){
			print OUT "\tdo i = 1,$nclust_included\n";
			print OUT "\t\tf(i) = f(i)+source(i)";
			if($l_use_get_losses){
				print OUT "-loss(i)*c(i)";
			}
			print OUT "\n\tend do\n";
			if($nmol_types_used>1){
				print OUT "\tdo imol = 1,$nmol_types_used\n";
				print OUT "\t\ti = n_monomers(imol)\n";
			}else{
				print OUT "\tdo i = 1,1\n";
			}
			if(!$l_j_in){
				print OUT "\t\tdo j = 1,$nclust_included\n";
			}else{
				print OUT "\t\tdo j = n_j_in,$nclust_included\n";
			}
		}else{
			if(!$l_j_in){
				print OUT "\tdo i = 1,$nclust_included\n";
			}else{
				print OUT "\tdo i = n_j_in,$nclust_included\n";
				print OUT "\t\t! collisions among clusters taken into account in the distribution\n";
			}
			print OUT "\t\tf(i) = f(i)+source(i)";
			if($l_use_get_losses){
				print OUT "-loss(i)*c(i)";
			}
			print OUT "\n";
			print OUT "\t\tdo j = i,$nclust_included\n";
		}
		if($nmol_types_used>1){
			print OUT "\t\t\tij_ind = indices(i,:)+indices(j,:)\n";
			print OUT "\t\t\tif (clust_from_indices($nmol_ranges_ij_ind) .eq. 0) then\n";
			if($lloop_cs){
				print OUT "\t\t\t\tij_ind = ij_ind_cs\n";
			}else{
				print OUT "\t\t\t\tij = $n_flux_out\n";
			}
			if ($lloop_boundary){
				print OUT "\t\t\telse if (clust_from_indices($nmol_ranges_ij_ind) .eq. -1) then\n";
				print OUT "\t\t\t\tcycle\n";
			}
			if($lloop_cs){
				print OUT "\t\t\tend if\n";
				print OUT "\t\t\tij = clust_from_indices($nmol_ranges_ij_ind)\n";
			}else{
				print OUT "\t\t\telse\n";
				print OUT "\t\t\t\tij = clust_from_indices($nmol_ranges_ij_ind)\n";
				print OUT "\t\t\tend if\n";
			}
		}else{
			print OUT "\t\t\tij = min($n_flux_out,i+j)\n";
		}
		# Printing out the indices in the rate constant matrices as (j,i) instead of (i,j) for speed,
		# as Fortran is column-major
		print OUT "\t\t\tf(i) = f(i)-K(j,i)*c(i)*c(j)\n";
		print OUT "\t\t\tf(j) = f(j)-K(j,i)*c(i)*c(j)\n";
		print OUT "\t\t\tf(ij) = f(ij)+K(j,i)*c(i)*c(j)\n";
		# Create a string containing the condition for evaporation of cluster i+j (if (...) then)
        if($disable_nonmonomer_evaps && $nmol_types_used==1){
            $lines{'l_evap'} = "if (i .eq. 1) then\n";
        }else{
            $lines{'l_evap'} = "if (E(j,i) .gt. 0.d0) then\n";
        }
		if(!$disable_evap){
			print OUT "\t\t\t$lines{'l_evap'}";
			print OUT "\t\t\t\tf(i) = f(i)+E(j,i)*c(ij)\n";
			print OUT "\t\t\t\tf(j) = f(j)+E(j,i)*c(ij)\n";
			print OUT "\t\t\t\tf(ij) = f(ij)-E(j,i)*c(ij)\n";
			print OUT "\t\t\tend if\n";
		}
		print OUT "\t\tend do\n";
		if($l_j_in && !$disable_nonmonomers){
			# Deal with the clusters colliding with a monomer here, since the monomer isn't included in the equation loop
			# when all collisions are taken into account
			print OUT "\t\t! monomer collisions\n";
			print OUT "\t\tj = 1\n";
			print OUT "\t\tij = min($n_flux_out,i+j)\n";
			print OUT "\t\tf(i) = f(i)-K(j,i)*c(i)*c(j)\n";
			print OUT "\t\tf(j) = f(j)-K(j,i)*c(i)*c(j)\n";
			print OUT "\t\tf(ij) = f(ij)+K(j,i)*c(i)*c(j)\n";
			if(!$disable_evap){
				print OUT "\t\t$lines{'l_evap'}";
				print OUT "\t\t\tf(i) = f(i)+E(j,i)*c(ij)\n";
				print OUT "\t\t\tf(j) = f(j)+E(j,i)*c(ij)\n";
				print OUT "\t\t\tf(ij) = f(ij)-E(j,i)*c(ij)\n";
				print OUT "\t\tend if\n";
			}
		}
		if($lgrowth_for_j_tests){
			print OUT "\t\t! collisions with the implicit growth compound\n";
			print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,i)\n";
			print OUT "\t\tif (r .ge. $rlim_growth_compound_str) then\n";
			print OUT "\t\t\tj = 2\n";
			print OUT "\t\t\tij = min($n_flux_out,i+j)\n";
			print OUT "\t\t\tf(i) = f(i)-K(j,i)*c(i)*$c_growth_compound_str\n";
			print OUT "\t\t\tf(ij) = f(ij)+K(j,i)*c(i)*$c_growth_compound_str\n";
			print OUT "\n";
			print OUT "\t\t\tj = 3\n";
			print OUT "\t\t\tij = min($n_flux_out,i+j)\n";
			print OUT "\t\t\tf(i) = f(i)-K(j,i)*c(i)*$c_growth_compound_str\n";
			print OUT "\t\t\tf(ij) = f(ij)+K(j,i)*c(i)*$c_growth_compound_str\n";
			print OUT "\t\tend if\n";
		}
		print OUT "\tend do\n";
		print OUT "\tdo i = 1,$nclust_included\n";
		print OUT "\t\tif (isconst(i)) then\n";
		print OUT "\t\t\tf(i) = 0.d0\n";
		print OUT "\t\tend if\n";
		print OUT "\tend do\n";
		if(!$lloop_cs && !$l_save_outgoing){
			print OUT "\tf_out = f(1:$nclust_included)\n";
		}
	}else{
		print OUT "\tf = 0.d0\n";
        $str_temp = "\tdo i = 1, neqn";
        if($l_save_coag_per_clust || $l_save_outgoing_clust){
            # Do not include the optional last elements that don't have their own coefficient / index arrays
            $str_temp .= "-".($n_coag_per_clust+$n_out_clust);
        }
        $str_temp .= " ! loop over all the clusters";
		if($include_generic_neg && $include_generic_pos){
			if($generic_positive_ions_corr ne ''){
				print OUT "\n\t! setting positive charger ion concentration to give charge balance\n";
				print OUT "\tif (c($n_generic_neg)+$generic_positive_ions_corr>0) then\n";
				print OUT "\tc($n_generic_pos) = c($n_generic_neg)+$generic_positive_ions_corr\n";
				print OUT "\telse\n";
				print OUT "\t\tc($n_generic_neg) = -($generic_positive_ions_corr)\n";
				print OUT "\t\tc($n_generic_pos) = 0\n";
				print OUT "\tend if\n\n";
			}elsif($generic_negative_ions_corr ne ''){
				print OUT "\n\t! setting negative charger ion concentration to give charge balance\n";
				print OUT "\tif (c($n_generic_pos)+$generic_negative_ions_corr>0) then\n";
				print OUT "\tc($n_generic_neg) = c($n_generic_pos)+$generic_negative_ions_corr\n";
				print OUT "\telse\n";
				print OUT "\t\tc($n_generic_pos) = -($generic_negative_ions_corr)\n";
				print OUT "\t\tc($n_generic_neg) = 0\n";
				print OUT "\tend if\n\n";
			}elsif($generic_positive_ions ne ''){
				print OUT "\n\t! setting positive charger ion concentration to give charge balance\n";
				print OUT "\tc($n_generic_pos) = $generic_positive_ions\n\n";
			}elsif($generic_negative_ions ne ''){
				print OUT "\n\t! setting negative charger ion concentration to give charge balance\n";
				print OUT "\tc($n_generic_neg) = $generic_negative_ions\n\n";
			}
			if($l_q_neg_mcmc){
				print OUT "\n\t! negative charger ion source term from mcmc coefficient\n";
				print OUT "\tsource($n_generic_neg) = coef(" . ($ncoef_coll+$ncoef_evap+1) . ")\t\t\t\t! Q_{neg}\n\n";
			}
			if($l_q_pos_mcmc){
				print OUT "\n\t! positive charger ion source term from mcmc coefficient\n";
				print OUT "\tsource($n_generic_pos) = coef(" . ($ncoef_coll+$ncoef_evap+$l_q_neg_mcmc+1) . ")\t\t\t\t! Q_{pos}\n\n";
			}
            $str_temp .= " + generic charger ions";
		}
        if($l_save_outgoing){
            $str_temp .= " + other fluxes";
        }
        print OUT "$str_temp\n";
		print OUT "\t\tif (.not. isconst(i)) then\n";
		print OUT "\t\t\t! first calculate coefficients for all loss terms\n";
		print OUT "\t\t\tdo n = 1, 2*ind_quad_loss(i,0)-1, 2 ! loop over all collisions removing this cluster\n";
		print OUT "\t\t\t\tf(i) = f(i)-coef_quad(i,ind_quad_loss(i,n),ind_quad_loss(i,n+1))*c(ind_quad_loss(i,n))\n";
		print OUT "\t\t\tend do\n";
		print OUT "\t\t\tdo n = 1, 2*ind_lin_loss(i,0)-1, 2 ! loop over all evaporations + wall losses etc. removing this cluster\n";
		print OUT "\t\t\t\tf(i) = f(i)-coef_lin(ind_lin_loss(i,n),ind_lin_loss(i,n+1),i)\n";
		print OUT "\t\t\tend do\n";
		print OUT "\t\t\tf(i) = f(i)*c(i) ! multiplying loss coefficients with current concentration\n";
		print OUT "\t\t\t! then add all terms that form this cluster\n";
		print OUT "\t\t\tdo n = 1, 2*ind_quad_form(i,0)-1, 2 ! loop over all collisions forming this cluster\n";
		print OUT "\t\t\t\tf(i) = f(i)+coef_quad(ind_quad_form(i,n),ind_quad_form(i,n+1),i)*&\n";
		print OUT "\t\t\t\t&      c(ind_quad_form(i,n))*c(ind_quad_form(i,n+1))\n";
		print OUT "\t\t\tend do\n";
		print OUT "\t\t\tdo n = 1, 3*ind_quad_form_extra(i,0)-2, 3 ! loop over all collisions forming this cluster as an extra product\n";
		print OUT "\t\t\t\tf(i) = f(i)+coef_quad(ind_quad_form_extra(i,n),ind_quad_form_extra(i,n+1),i)*&\n";
		print OUT "\t\t\t\t&      n_quad_form_extra(i,(n+2)/3)*c(ind_quad_form_extra(i,n))*c(ind_quad_form_extra(i,n+1))\n";
		print OUT "\t\t\tend do\n";
		print OUT "\t\t\tdo n = 1, 2*ind_lin_form(i,0)-1, 2 ! loop over all evaporations forming this cluster\n";
		print OUT "\t\t\t\tf(i) = f(i)+coef_lin(i,ind_lin_form(i,n),ind_lin_form(i,n+1))*c(ind_lin_form(i,n+1))\n";
		print OUT "\t\t\tend do\n";
		print OUT "\t\t\t! finally, add possible external sources\n";
		print OUT "\t\t\tf(i) = f(i) + source(i)\n";
		print OUT "\t\tend if\n";
		print OUT "\tend do\n";
        if($l_save_coag_per_clust){
            print OUT "\t! coagulation for each cluster\n";
            print OUT "\ti = $n_flux_coag\n";
            print OUT "\tdo n = 1, 2*ind_lin_form(i,0)-1, 2 ! loop over all coagulations\n";
            print OUT "\t\tj = ".($range_coag_per_clust[0]-1)."+ind_lin_form(i,n+1)\n";
            print OUT "\t\tf(j) = f(j)+coef_lin(i,ind_lin_form(i,n),ind_lin_form(i,n+1))*c(ind_lin_form(i,n+1))\n";
            print OUT "\tend do\n";
        }
        if($l_save_outgoing_clust){
            print OUT "\t! flux out for each outgrown cluster\n";
            print OUT "\tdo i = $n_flux_out, $n_flux_out_max ! loop over all charging states\n";
            print OUT "\t\tdo n = 1, 2*ind_quad_form(i,0)-1, 2 ! loop over all collisions going out through this channel\n";
            print OUT "\t\t\tj = ".($range_out_clust[0]-1)."+ind_out_clust(ind_quad_form(i,n),ind_quad_form(i,n+1))\n";
            print OUT "\t\t\tf(j) = f(j)+coef_quad(ind_quad_form(i,n),ind_quad_form(i,n+1),i)*&\n";
            print OUT "\t\t\t&      c(ind_quad_form(i,n))*c(ind_quad_form(i,n+1))\n";
            print OUT "\t\tend do\n";
            print OUT "\tend do\n";
        }
	}
    print OUT "\t! loop over the clusters whose concentrations are fitted (e.g. [1A]+[1A1D]=const.)\n";
	print OUT "\tdo n = 1, fitted(1,0)\n";
	if($l_j_in){
		print OUT "\t\tif ((fitted(n+1,0) .ne. 1) .and. (fitted(n+1,0) .lt. n_j_in)) then\n";
		print OUT "\t\t\tcycle\n";
		print OUT "\t\tend if\n";
	}
	print OUT "\t\tf(fitted(n+1,0)) = 0.d0 ! don't use value from birth-death equations\n";
	print OUT "\t\tdo i = 1, fitted(n+1,1) ! loop over the clusters used for the fitting\n";
	print OUT "\t\t\tf(fitted(n+1,0)) = f(fitted(n+1,0))-f(fitted(n+1,i+1)) ! (e.g. d[1A]/dt = -d[1A1D]/dt)\n";
	print OUT "\t\tend do\n";
	print OUT "\tend do\n";
	print OUT "\nend subroutine feval$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
	
	print OUT "! jacobian of the differential equations: dfdc(i,j) = df(i)/dc(j)\n! not using this, since the solver works faster using a numerical jacobian...\n";
	print OUT "subroutine jeval$append_to_eq_names(neqn,t,c,ml,mu,dfdc,ldim,coef,ipar)\n";
	print OUT "\timplicit none\n\tinteger :: ldim,neqn,ierr,ipar(4),i,j,k,n\n";
	print OUT "\treal(kind(1.d0)) :: t,c(neqn),dfdc(ldim,neqn)";
	if($l_mcmc_any){
		print OUT ",coef(" . ($n_mcmc_coefs+$variable_cs+2*$variable_ion_source) . ")";
	}elsif($l_variable_parameters){
		print OUT ",coef($n_variable_parameters)";
	}else{
		print OUT ",coef(:)";
	}
	print OUT ",ml,mu\n";
	print OUT "\nend subroutine jeval$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
}

################################################################################
################################################################################
##      8.3 Determining if parameters for ions are used in the Matlab files   ##
################################################################################
################################################################################

# Check if we have ions; if not, don't print stuff related to them to the Matlab files
if(!$lfortran){
	if(!$include_ion_terms){
		# Input for the equation and flux files
		$input_for_eq='t,c,K,E,WL,CS,source,isconst,isfitted,C_fit';
		# this is for the case where a function is given for the concentration of some cluster
		$input_for_eq_C_fun='K,E,WL,CS,source,isconst,isfitted,C_fit';
		$input_for_flux='c,K,E,WL,CS,source,calc_sources';
	}else{
		$input_for_eq='t,c,K,E,WL,CS,source,isconst,isfitted,C_fit,fwl,fcs';
		$input_for_eq_C_fun='K,E,WL,CS,source,isconst,isfitted,C_fit,fwl,fcs';
		$input_for_flux='c,K,E,WL,CS,source,calc_sources,fwl,fcs';
	}
	if($l_reac_in_clus){
		$input_for_eq =~ s/K,E,/K,E,R,/;
		$input_for_eq_C_fun =~ s/K,E,/K,E,R,/;
		$input_for_flux =~ s/K,E,/K,E,R,/;
	}
	if($#source_function>=0){
		$input_for_flux =~ s/^c,/c,t,/;
	}

################################################################################
################################################################################
##      8.4 dC/dt for Matlab                                                  ##
################################################################################
################################################################################

	open(OUT, ">$output_file_name") || die "\nCould not open output file $output_file_name\n\n";
	
	print OUT "function cdot = $output_function_name($input_for_eq)\n\n%%%%%%%%%%%%%%%%%%%%% KEY %%%%%%%%%%%%%%%%\n";
	
	# Printing the key of what equation is what
	for($iclus=1;$iclus<=$max_n_flux;$iclus++){
		print OUT "$comments[$iclus]\n";
	}
	print OUT "%%%%%%%%%%%%%%%%%%%%% END KEY %%%%%%%%%%%%%%%%\n\n";

	print OUT "% Temperature = $temperature K\n\n";
	if(!$disable_dilution){
		print OUT "dil = $dil_str;\n\n";
	}

	print OUT "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n%%% Begin Equations Here\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\ncdot = zeros(size(c));\n\n";
	
	# Fitting generic positive or negative ions to give charge balance
	if($include_generic_neg && $include_generic_pos){
		if($generic_positive_ions_corr ne ''){
			print OUT "% setting positive charger ion concentration to give charge balance\n";
			print OUT "if c($n_generic_neg)+$generic_positive_ions_corr>0\n";
			print OUT "c($n_generic_pos) = c($n_generic_neg)+$generic_positive_ions_corr;\n\n";
			print OUT "else\n";
			print OUT "\tc($n_generic_neg) = -($generic_positive_ions_corr);\n";
			print OUT "\tc($n_generic_pos) = 0;\n";
			print OUT "end\n\n";
			print OUT "isconst($n_generic_pos) = 1;\n\n";
		}elsif($generic_negative_ions_corr ne ''){
			print OUT "% setting negative charger ion concentration to give charge balance\n";
			print OUT "if c($n_generic_pos)+$generic_negative_ions_corr>0\n";
			print OUT "c($n_generic_neg) = c($n_generic_pos)+$generic_negative_ions_corr;\n\n";
			print OUT "else\n";
			print OUT "\tc($n_generic_pos) = -($generic_negative_ions_corr);\n";
			print OUT "\tc($n_generic_neg) = 0;\n";
			print OUT "end\n\n";
			print OUT "isconst($n_generic_neg) = 1;\n\n";
		}elsif($generic_positive_ions ne ''){
			print OUT "% setting positive charger ion concentration to give charge balance\n";
			print OUT "c($n_generic_pos) = $generic_positive_ions;\n";
			print OUT "isconst($n_generic_pos) = 1;\n\n";
		}elsif($generic_negative_ions ne ''){
			print OUT "% setting negative charger ion concentration to give charge balance\n";
			print OUT "c($n_generic_neg) = $generic_negative_ions;\n";
			print OUT "isconst($n_generic_neg) = 1;\n\n";
		}
	}

	# Equations for keeping a sum of concentrations constant
	print OUT "% Equations for keeping a sum of concentrations constant\n";
	print OUT "if any(isfitted)\n";
	print OUT "\tfor i = 1:$max_cluster_number\n";
	print OUT "\t\tif isfitted(i)\n";
	print OUT "\t\t\tc(i) = C_fit{i,1}-sum(c(C_fit{i,2}));\n";
	print OUT "\t\t\tif c(i) < 0\n";
	print OUT "\t\t\t\tc(C_fit{i,2}) = c(C_fit{i,2})*C_fit{i,1}/sum(c(C_fit{i,2}));\n";
	print OUT "\t\t\t\tc(i) = 0;\n";
	print OUT "\t\t\tend\n";
	print OUT "\t\tend\n";
	print OUT "\tend\n";
	print OUT "end\n\n";
	print OUT "$lines{'source'}";

	# Looping through the equations for all clusters and charger ions + the outgoing flux
	for($iclus=1;$iclus<=$max_n_flux;$iclus++){
		if($iclus>$max_cluster_number && (($ind_quad_form[$iclus][0]==0 && $ind_lin_form[$iclus][0]==0) || $iclus==$n_flux_rec)){
			next;
		}
		print OUT "\n$comments[$iclus]\n";
		if($iclus > $max_cluster_number){
			$line = "cdot($iclus) =";
		}else{
			$line = "if isconst($iclus),\n\tcdot($iclus) = 0;\nelse\n\tcdot($iclus) = source($iclus)";
		}
		$line_temp = "";
		# Losses in collisions
		for($i=1;$i<=2*$ind_quad_loss[$iclus][0];$i+=2){
			$jclus = $ind_quad_loss[$iclus][$i];
			$kclus = $ind_quad_loss[$iclus][$i+1];
			if($iclus == $jclus){
				$str_temp = "2*" . $coef_quad{"$iclus,$jclus,$kclus"} . "*c($iclus)*c($jclus)";
			}else{
				$str_temp = $coef_quad{"$iclus,$jclus,$kclus"} . "*c($iclus)*c($jclus)";
			}
			# Adding blank spaces to make all terms the same length -> output easier to read
			$line_temp = "$line_temp- $str_temp " . ' ' x max(30-length($str_temp),0);
			# Only three terms per line -> output easier to read
			if(($i+1)%6==0){
				$line = "$line...\n\t\t$line_temp";
				$line_temp = "";
			}
		}
		if($line_temp ne ''){
			$line = "$line...\n\t\t$line_temp";
			$line_temp = "";
		}
		# Formation in collisions
		for($i=1;$i<=2*$ind_quad_form[$iclus][0];$i+=2){
			$jclus = $ind_quad_form[$iclus][$i];
			$kclus = $ind_quad_form[$iclus][$i+1];
			if(exists $coef_quad_form{"$jclus,$kclus,$iclus"}){
				$str_temp = $coef_quad_form{"$jclus,$kclus,$iclus"} . "*c($jclus)*c($kclus)";
			}else{
				$str_temp = $coef_quad{"$jclus,$kclus,$iclus"} . "*c($jclus)*c($kclus)";
			}
			$line_temp = "$line_temp+ $str_temp " . ' ' x max(30-length($str_temp),0);
			if(($i+1)%6==0){
				$line = "$line...\n\t\t$line_temp";
				$line_temp = "";
			}
		}
		if($line_temp ne ''){
			$line = "$line...\n\t\t$line_temp";
			$line_temp = "";
		}
		# Extra formation in boundary collisions
		for($i=1;$i<=3*$ind_quad_form_extra[$iclus][0];$i+=3){
			$jclus = $ind_quad_form_extra[$iclus][$i];
			$kclus = $ind_quad_form_extra[$iclus][$i+1];
			if(exists $coef_quad_form{"$jclus,$kclus,$iclus"}){
				$str_temp = $coef_quad_form{"$jclus,$kclus,$iclus"} . "*c($jclus)*c($kclus)";
			}elsif($ind_quad_form_extra[$iclus][$i+2] != 1){
				$str_temp = $ind_quad_form_extra[$iclus][$i+2] . "*" . $coef_quad{"$jclus,$kclus,$iclus"} . "*c($jclus)*c($kclus)";
			}else{
				$str_temp = $coef_quad{"$jclus,$kclus,$iclus"} . "*c($jclus)*c($kclus)";
			}
			$line_temp = "$line_temp+ $str_temp " . ' ' x max(30-length($str_temp),0);
			if(($i+2)%9==0){
				$line = "$line...\n\t\t$line_temp";
				$line_temp = "";
			}
		}
		if($line_temp ne ''){
			$line = "$line...\n\t\t$line_temp";
			$line_temp = "";
		}
		# Losses by evaporation or external sinks
		for($i=1;$i<=2*$ind_lin_loss[$iclus][0];$i+=2){
			$jclus = $ind_lin_loss[$iclus][$i];
			$kclus = $ind_lin_loss[$iclus][$i+1];
			$str_temp = $coef_lin{"$jclus,$kclus,$iclus"} . "*c($iclus)";
			$line_temp = "$line_temp- $str_temp " . ' ' x max(30-length($str_temp),0);
			if(($i+1)%6==0){
				$line = "$line...\n\t\t$line_temp";
				$line_temp = "";
			}
		}
		if($line_temp ne ''){
			$line = "$line...\n\t\t$line_temp";
			$line_temp = "";
		}
		# Formation from evaporations
		for($i=1;$i<=2*$ind_lin_form[$iclus][0];$i+=2){
			$jclus = $ind_lin_form[$iclus][$i];
			$kclus = $ind_lin_form[$iclus][$i+1];
			if($iclus == $jclus && $iclus<=$max_cluster_number){
				$str_temp = "2*" . $coef_lin{"$iclus,$jclus,$kclus"} . "*c($kclus)";
			}else{
				$str_temp = $coef_lin{"$iclus,$jclus,$kclus"} . "*c($kclus)";
			}
			$line_temp = "$line_temp+ $str_temp " . ' ' x max(30-length($str_temp),0);
			if(($i+1)%6==0){
				$line = "$line...\n\t\t$line_temp";
				$line_temp = "";
			}
		}
		if($line_temp ne ''){
			$line = "$line...\n\t\t$line_temp";
			$line_temp = "";
		}
		# Losses by reactions inside clusters
		for($i=1;$i<=2*$ind_reac_loss[$iclus][0];$i+=2){
			$jclus = $ind_reac_loss[$iclus][$i];
			$str_temp = "R($iclus,$jclus)*c($iclus)";
			$line_temp = "$line_temp- $str_temp " . ' ' x max(30-length($str_temp),0);
			if(($i+1)%6==0){
				$line = "$line...\n\t\t$line_temp";
				$line_temp = "";
			}
		}
		if($line_temp ne ''){
			$line = "$line...\n\t\t$line_temp";
			$line_temp = "";
		}
		# Formation by reactions inside clusters
		for($i=1;$i<=2*$ind_reac_form[$iclus][0];$i+=2){
			$kclus = $ind_reac_form[$iclus][$i+1];
			$str_temp = "R($kclus,$iclus)*c($kclus)";
			$line_temp = "$line_temp+ $str_temp " . ' ' x max(30-length($str_temp),0);
			if(($i+1)%6==0){
				$line = "$line...\n\t\t$line_temp";
				$line_temp = "";
			}
		}
		if($line_temp ne ''){
			$line = "$line...\n\t\t$line_temp";
			$line_temp = "";
		}
		$line = "$line;\n";
		if($iclus<=$max_cluster_number){
			$line = $line . "end\n";
		}
		print OUT $line;
	}
	
	#Equations for keeping a sum of concentrations constant
	print OUT "\n\n% Equations for keeping a sum of concentrations constant\n";
	print OUT "if any(isfitted)\n";
	print OUT "\tfor i = 1:$max_cluster_number\n";
	print OUT "\t\tif isfitted(i)\n";
	print OUT "\t\t\tcdot(i) = -sum(cdot(C_fit{i,2}));\n";
	print OUT "\t\tend\n";
	print OUT "\tend\n";
	print OUT "end\n";
	print OUT "\nend\n";
	close(OUT);

################################################################################
################################################################################
##      8.5 Fluxes for Matlab                                                 ##
################################################################################
################################################################################

	open(FLUX, ">$flux_file_name") || die "\nCould not open flux file $flux_file_name\n\n";
	
	print FLUX "function [flux_2d, coll_evap_2d, sources, flux_3d, flux_out, clust_flux] = $flux_function_name($input_for_flux)\n\n%%%%%%%%%%%%%%%%%%%%% KEY %%%%%%%%%%%%%%%%\n";
	
	# Printing the key of what equation is what
	for($iclus=1;$iclus<=$max_n_flux_inc_boundary_clusters;$iclus++){
		print FLUX "$comments[$iclus]\n";
	}
	print FLUX "%%%%%%%%%%%%%%%%%%%%% END KEY %%%%%%%%%%%%%%%%\n\n";
	
	# print out the vector containing the cluster names plus the names of the other fluxes (sources, losses etc.)
	$line = "% name vector containing all the names (clusters, sources, losses etc.) in the flux matrices\nclust_flux = {";
	for($iclus=1;$iclus<=$max_n_flux_inc_boundary_clusters;$iclus++){
		$line = $line . "'" . $label_inc_boundary_clusters[$iclus] . "' ";
	}
	$line = "$line};\n\n";
	print FLUX $line;
	
	if(!$disable_dilution){
		print FLUX "dil = $dil_str;\n\n";
	}
	
	print FLUX "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n%%% Begin Equations Here\n%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n";
	
	if($include_generic_neg && $include_generic_pos){
		if($generic_positive_ions_corr ne ''){
			print FLUX "% setting positive charger ion concentration to give charge balance\n";
			print FLUX "if c($n_generic_neg)+$generic_positive_ions_corr>0\n";
			print FLUX "c($n_generic_pos) = c($n_generic_neg)+$generic_positive_ions_corr;\n\n";
			print FLUX "else\n";
			print FLUX "\tc($n_generic_neg) = -($generic_positive_ions_corr);\n";
			print FLUX "\tc($n_generic_pos) = 0;\n";
			print FLUX "end\n\n";
		}elsif($generic_negative_ions_corr ne ''){
			print FLUX "% setting negative charger ion concentration to give charge balance\n";
			print FLUX "if c($n_generic_pos)+$generic_negative_ions_corr>0\n";
			print FLUX "c($n_generic_neg) = c($n_generic_pos)+$generic_negative_ions_corr;\n\n";
			print FLUX "else\n";
			print FLUX "\tc($n_generic_pos) = -($generic_negative_ions_corr);\n";
			print FLUX "\tc($n_generic_neg) = 0;\n";
			print FLUX "end\n\n";
		}elsif($generic_positive_ions ne ''){
			print FLUX "% setting positive charger ion concentration to give charge balance\n"; 
			print FLUX "c($n_generic_pos) = $generic_positive_ions;\n";
			print FLUX "isconst($n_generic_pos) = 1;\n\n";
		}elsif($generic_negative_ions ne ''){
			print FLUX "% setting negative charger ion concentration to give charge balance\n";
			print FLUX "c($n_generic_neg) = $generic_negative_ions;\n";
			print FLUX "isconst($n_generic_neg) = 1;\n\n";
		}
	}

	print FLUX "flux_2d = zeros($max_n_flux_inc_boundary_clusters,$max_n_flux_inc_boundary_clusters);\n";
	if($print_3d_flux){
		print FLUX "flux_3d = zeros($max_n_flux_inc_boundary_clusters,$max_n_flux_inc_boundary_clusters,$max_n_flux_inc_boundary_clusters);\n";
	}else{
		print FLUX "flux_3d = [];\n";
	}
	print FLUX "coll_evap_2d = zeros($max_n_flux_inc_boundary_clusters,$max_n_flux_inc_boundary_clusters);\n";
	print FLUX "flux_out = zeros($max_cluster_number,$max_cluster_number,4);\n";
	print FLUX "sources = zeros($max_cluster_number,1);\n$lines{'source'}";
	
	if($print_3d_flux){
		print FLUX "% Note on 3D boundary fluxes:\n";
		print FLUX "% if you're keeping the boundary clusters, these are not working!\n";
		print FLUX "% sum(flux_3d(i,j,:)) is correct\n";
		print FLUX "% sum(flux_3d(:,:,k)) is correct but some of it comes from the boundary as flux_3d((index of the boundary cluster),(index of the boundary cluster),k)\n";
		print FLUX "% flux_3d(i,j,k1)/flux_3d(i,j,k2) is correct\n\n";
	}
	
	# Looping through the equations
	for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
		print FLUX "\n$comments[$iclus]\n";
		if($ind_quad_loss[$iclus][0]>0){
			print FLUX "\t% Collisions removing this cluster\n";
		}
		# Losses in collisions + corresponding formation
		for($i=1;$i<=2*$ind_quad_loss[$iclus][0];$i+=2){
			$jclus = $ind_quad_loss[$iclus][$i];
			$kclus = $ind_quad_loss[$iclus][$i+1];
			$str_temp = $coef_quad{"$iclus,$jclus,$kclus"} . "*c($iclus)*c($jclus);\n";
			if(exists $coef_quad_form{"$iclus,$jclus,$kclus"}){
				$str_temp_form = $coef_quad_form{"$iclus,$jclus,$kclus"} . "*c($iclus)*c($jclus);\n";
			}else{
				$str_temp_form = $str_temp;
			}
			if($iclus==$jclus){
				# 2d-fluxes have a factor 2 for collisions of identical clusters except in fluxes from the boundary
				$str_temp2 = "2*$str_temp";
			}else{
				$str_temp2 = $str_temp;
			} 
			if(exists $l_quad_bound{"$iclus,$jclus,$kclus"} || exists $l_quad_nst{"$iclus,$jclus,$kclus"}){
				# 2-d fluxes to boundary and from boundary to the main product
				if(exists $l_quad_bound{"$iclus,$jclus,$kclus"} && $keep_boundary_clusters){
					$kclus_bound = $clus_bound_ind{"$iclus,$jclus,$kclus"};
					if($iclus<=$jclus && $print_3d_flux){
						print FLUX "\tflux_3d($iclus,$jclus,$kclus_bound) = flux_3d($iclus,$jclus,$kclus_bound)+1/$n_coll_products[$iclus][$jclus]*$str_temp_form";
						print FLUX "\tflux_3d($kclus_bound,$kclus_bound,$kclus) = flux_3d($kclus_bound,$kclus_bound,$kclus)+(1-1/$n_coll_products[$iclus][$jclus])*$str_temp_form";
					}
					print FLUX "\tcoll_evap_2d($iclus,$kclus_bound) = coll_evap_2d($iclus,$kclus_bound)+$str_temp2";
					# Print the fluxes from the boundary only once
					if($iclus>=$jclus){
						print FLUX "\tcoll_evap_2d($kclus_bound,$kclus) = coll_evap_2d($kclus_bound,$kclus)+$str_temp_form";
					}
				}else{
					if($iclus<=$jclus && $print_3d_flux){
						print FLUX "\tflux_3d($iclus,$jclus,$kclus) = flux_3d($iclus,$jclus,$kclus)+1/$n_coll_products[$iclus][$jclus]*$str_temp_form";
						print FLUX "\tflux_3d($n_flux_bound,$n_flux_bound,$kclus) = flux_3d($n_flux_bound,$n_flux_bound,$kclus)+(1-1/$n_coll_products[$iclus][$jclus])*$str_temp_form";
					}
					print FLUX "\tcoll_evap_2d($iclus,$n_flux_bound) = coll_evap_2d($iclus,$n_flux_bound)+$str_temp2";
					# Print the fluxes from the boundary only once
					if($iclus>=$jclus){
						print FLUX "\tcoll_evap_2d($n_flux_bound,$kclus) = coll_evap_2d($n_flux_bound,$kclus)+$str_temp_form";
					}
				}
			}else{
				if($iclus<=$jclus && $print_3d_flux){
					print FLUX "\tflux_3d($iclus,$jclus,$kclus) = flux_3d($iclus,$jclus,$kclus)+$str_temp";
				}
				print FLUX "\tcoll_evap_2d($iclus,$kclus) = coll_evap_2d($iclus,$kclus)+$str_temp2";
			}
		}
		# Extra loss pathways in boundary collisions + corresponding formation
		if($ind_quad_loss_extra[$iclus][0]>0){
			print FLUX "\t% More products from the same collisions (monomers from the boundary etc.)\n";
		}
		for($i=1;$i<=3*$ind_quad_loss_extra[$iclus][0];$i+=3){
			$jclus = $ind_quad_loss_extra[$iclus][$i];
			# Print these only once
			if($iclus<=$jclus && !($i>1 && $jclus==$ind_quad_loss_extra[$iclus][$i-3])){
				$kclus = $ind_quad_loss_extra[$iclus][$i+1];
				if(exists $coef_quad_form{"$iclus,$jclus,$kclus"}){
					$str_temp_form = $coef_quad_form{"$iclus,$jclus,$kclus"} . "*c($iclus)*c($jclus);\n";
				}else{
					$str_temp_form = $coef_quad{"$iclus,$jclus,$kclus"} . "*c($iclus)*c($jclus);\n";
				}
				if($print_3d_flux){
					if(exists $l_quad_bound{"$iclus,$jclus,$kclus"} && $keep_boundary_clusters){
						$kclus_bound = $clus_bound_ind{"$iclus,$jclus,$kclus"};
						print FLUX "\tflux_3d($iclus,$jclus,$kclus_bound) = flux_3d($iclus,$jclus,$kclus_bound)+$ind_quad_loss_extra[$iclus][$i+2]/$n_coll_products[$iclus][$jclus]*$str_temp_form";
						print FLUX "\tflux_3d($kclus_bound,$kclus_bound,$kclus) = flux_3d($kclus_bound,$kclus_bound,$kclus)+$ind_quad_loss_extra[$iclus][$i+2]*(1-1/$n_coll_products[$iclus][$jclus])*$str_temp_form";
					}else{
						print FLUX "\tflux_3d($iclus,$jclus,$kclus) = flux_3d($iclus,$jclus,$kclus)+$ind_quad_loss_extra[$iclus][$i+2]/$n_coll_products[$iclus][$jclus]*$str_temp_form";
						print FLUX "\tflux_3d($n_flux_bound,$n_flux_bound,$kclus) = flux_3d($n_flux_bound,$n_flux_bound,$kclus)+$ind_quad_loss_extra[$iclus][$i+2]*(1-1/$n_coll_products[$iclus][$jclus])*$str_temp_form";
					}
				}
				if($ind_quad_loss_extra[$iclus][$i+2] != 1){
					$str_temp_form =  "$ind_quad_loss_extra[$iclus][$i+2]*$str_temp_form";
				}
				if(exists $l_quad_bound{"$iclus,$jclus,$kclus"} && $keep_boundary_clusters){
					$kclus_bound = $clus_bound_ind{"$iclus,$jclus,$kclus"};
					print FLUX "\tcoll_evap_2d($kclus_bound,$kclus) = coll_evap_2d($kclus_bound,$kclus)+$str_temp_form";
				}else{
					print FLUX "\tcoll_evap_2d($n_flux_bound,$kclus) = coll_evap_2d($n_flux_bound,$kclus)+$str_temp_form";
				}
			}
		}
		#  Formation by evaporation + corresponding losses
		if($ind_lin_form[$iclus][0]>0){
			print FLUX "\t% Evaporations resulting in this cluster\n";
		}
		for($i=1;$i<=2*$ind_lin_form[$iclus][0];$i+=2){
			$jclus = $ind_lin_form[$iclus][$i];
			$kclus = $ind_lin_form[$iclus][$i+1];
			$str_temp = $coef_lin{"$iclus,$jclus,$kclus"} . "*c($kclus);\n";
			if($iclus<=$jclus && $print_3d_flux){
				print FLUX "\tflux_3d($iclus,$jclus,$kclus) = flux_3d($iclus,$jclus,$kclus)-$str_temp";
			}
			if($iclus==$jclus){
				# 2d-fluxes have a factor 2 for evaporations producing identical clusters
				$str_temp = "2*$str_temp";
			} 
			print FLUX "\tcoll_evap_2d($kclus,$iclus) = coll_evap_2d($kclus,$iclus)+$str_temp";
		}
		# Losses to external sinks
		if(!$disable_wall_terms || !$disable_dilution || !$disable_coag_sinks){
			print FLUX "\t% External losses\n";
		}
		for($i=1;$i<=2*$ind_lin_loss[$iclus][0];$i+=2){
			$jclus = $ind_lin_loss[$iclus][$i];
			$kclus = $ind_lin_loss[$iclus][$i+1];
			if($jclus>$max_cluster_number){
				$str_temp = $coef_lin{"$jclus,$kclus,$iclus"} . "*c($iclus);\n";
				if($print_3d_flux){
					print FLUX "\tflux_3d($jclus,$kclus,$iclus) = flux_3d($jclus,$kclus,$iclus)-$str_temp";
				}
				print FLUX "\tcoll_evap_2d($iclus,$kclus) = coll_evap_2d($iclus,$kclus)+$str_temp";
			}
		}
		# Losses by reactions inside clusters + corresponding formation
		if($ind_reac_loss[$iclus][0]>0){
			print FLUX "\t% Chemical reactions removing this cluster\n";
		}
		for($i=1;$i<=2*$ind_reac_loss[$iclus][0];$i+=2){
			$jclus = $ind_reac_loss[$iclus][$i];
			$kclus = $ind_reac_loss[$iclus][$i+1];
			$str_temp = "R($iclus,$jclus)*c($iclus);\n";
			print FLUX "\tflux_3d($jclus,$kclus,$iclus) = flux_3d($jclus,$kclus,$iclus)-$str_temp";
			print FLUX "\tcoll_evap_2d($iclus,$jclus) = coll_evap_2d($iclus,$jclus)+$str_temp";
		}
	}

	# Flux matrix for outgoing collisions: flux_out(cluster 1, cluster 2, charge of formed big cluster)
	print FLUX "\n\n% Matrix for collisions that lead succesfully out of the system:\n% flux_out(i,j,k) is the outgoing flux from clusters i and j, where\n% k=1 for neutral-neutral, 2 for neutral-negative, 3 for neutral-positive and 4 for recombination collisions\n";
	for($k=$n_flux_out; $k<=$n_flux_out_max; $k++){
		for($i=1;$i<=2*$ind_quad_form[$k][0];$i+=2){
			$iclus = $ind_quad_form[$k][$i];
			$jclus = $ind_quad_form[$k][$i+1];
			if(exists $coef_quad_form{"$iclus,$jclus,$k"}){
				$line_temp = $coef_quad_form{"$iclus,$jclus,$k"} . "*c($iclus)*c($jclus);\n";
			}else{
				$line_temp = $coef_quad{"$iclus,$jclus,$k"} . "*c($iclus)*c($jclus);\n";
			}
			if($k==$n_flux_out && $lneutral_cluster[$iclus] && $lneutral_cluster[$jclus]){
				$j = 1;
			}elsif($k==$n_flux_out_neg){
				$j = 2;
			}elsif($k==$n_flux_out_pos){
				$j = 3;
			}else{
				$j = 4;
			}
			print FLUX "\tflux_out($iclus,$jclus,$j) = $line_temp";
		}
	}

	# Combine the collision and evaporation fluxes to net fluxes
	print FLUX "\n% Combining collisions and evaporations into net fluxes.\n";
	print FLUX "\tfor i = 1:" . ($max_n_flux_inc_boundary_clusters) . "\n\t\tfor j = (i+1):" . ($max_n_flux_inc_boundary_clusters) . "\n";
	print FLUX "\t\t\tnet = coll_evap_2d(i,j)-coll_evap_2d(j,i);\n\t\t\tif net > 0\n\t\t\t\tflux_2d(i,j) = net;\n\t\t\telse\n";
	print FLUX "\t\t\t\tflux_2d(j,i) = -net;\n\t\t\tend\n\t\tend\n\tend\n\n";
	
	# Adding source terms to the 2d flux matrices
	print FLUX "\n\n% Adding given source terms to the flux matrix and solving source terms of monomers, if needed\n";
	print FLUX "\tflux_2d($n_flux_source,1:$max_cluster_number) = source';\n\n";
	print FLUX "\tif calc_sources == 1\n";
	for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
		if ($lneutral_cluster[$iclus] && $lmonomer[$iclus]){
			print FLUX "\t\tsources($iclus) = sum(coll_evap_2d($iclus,:))-sum(coll_evap_2d([1:$max_n_flux_inc_boundary_clusters],$iclus));\n";
			print FLUX "\t\tif source($iclus) == 0\n\t\t\tflux_2d($n_flux_source,$iclus) = sources($iclus);\n\t\tend\n";
		}elsif($iclus==$n_generic_neg || $iclus==$n_generic_pos){
			print FLUX "\t\tsources($iclus) = sum(coll_evap_2d($iclus,:));\n";
			print FLUX "\t\tif source($iclus) == 0\n\t\t\tflux_2d($n_flux_source,$iclus) = sources($iclus);\n\t\tend\n";
		}
	}
	print FLUX "\tend\n";
	print FLUX "\nend\n";
	close(FLUX);
}

################################################################################
################################################################################
##      8.6 Formation rate for Fortran                                        ##
################################################################################
################################################################################

if($lfortran){
	print OUT "subroutine formation$append_to_eq_names(neqn,c";
	if($lloop){
		print OUT ",j_out";
		if($l_jlim){
			print OUT ",j_lim";
			if($lloop_j_frac){
				print OUT ",j_lim_frac";
			}
		}
	}else{
		print OUT ",j_tot,j_by_charge,j_by_cluster,j_all";
	}
	print OUT ",ipar";
	if($l_mcmc_any || $l_variable_parameters){
		print OUT ",coef";
	}
	print OUT ")\n";
	if($lloop && $disable_nonmonomers && $nmol_types_used>1){
		print OUT "use acdc_system$append_to_syst_names, only : monomer_indices$append_to_syst_names\n";
	}
	if($l_j_in){
		print OUT "use shared_input, only : r_j_in => rlim_for_J\n";
		print "\nUsing module shared_input in the formation subroutine to get r_j_in\n";
	}
	print OUT "\timplicit none\n";	
	print OUT "\tinteger, parameter :: nclust = $max_cluster_number";
	if($lloop && $nmol_types_used>1){
		print OUT ", ij_ind_max($nmol_types_used) = (/$nmol_ranges_list/)";
	}
	if($lloop_cs){
		if($nmol_types_used==1){
			print OUT ", n_cs = $max_cluster_number";
		}else{
			print OUT ", ij_ind_cs($nmol_types_used) = (/$nmol_cs_list/)";
		}
	}
	print OUT "\n";
	print OUT "\tinteger :: neqn, i";
	if($include_negative_ion_terms || $include_positive_ion_terms || $lloop){
		print OUT ", j";
	}
	if($lloop && $nmol_types_used>1){
		print OUT ", ij_ind($nmol_types_used), imol";
	}
	print OUT ", n, ipar(4)\n";
	if($lloop_j_tests || $lgrowth_for_j_tests || $l_j_in){
		print OUT "\treal(kind(1.d0)) :: r, m\n";
		if($l_j_in){
			print OUT "\tinteger, save :: n_j_in = 0\n";
		}
	}
	print OUT "\treal(kind(1.d0)) :: c(neqn)";
	if($lloop){
		print OUT ", j_out";
	}else{
		print OUT ", j_add, j_tot,j_by_charge(4),j_by_cluster(neqn),j_all(neqn,4)";
	}
	if($l_mcmc_any){
		print OUT ",coef(" . ($n_mcmc_coefs+$variable_cs+2*$variable_ion_source) . ")";
	}elsif($l_variable_parameters){
		print OUT ",coef($n_variable_parameters)";
	}
	print OUT "\n";
	if($lloop){
		if($lloop_restrict){
			print OUT "\treal(kind(1.d0)), save, allocatable :: K(:,:)";
			if($l_jlim && !$disable_evap){
				print OUT ", E(:,:)";
			}
		}else{
			print OUT "\treal(kind(1.d0)), save :: K(nclust,nclust)";
			if($l_jlim && !$disable_evap){
				print OUT ", E(nclust,";
				if($disable_nonmonomer_evaps && $nmol_types_used==1){
					print OUT "1)";
				}else{
					print OUT "nclust)";
				}
			}
		}
		print OUT "\n";
		if($nmol_types_used>1){
			print OUT "\tinteger, save :: nclust_inc=0, indices(nclust,$nmol_types_used)";
			print OUT ", clust_from_indices($nmol_comp_list)";
			if($disable_nonmonomers){
				print OUT ", n_monomers($nmol_types_used)";
			}
			print OUT "\n";
		}
	}else{
		print OUT "\treal(kind(1.d0)), save :: coef_quad(nclust,nclust,$size_ind_coef)=0.d0,coef_lin($size_ind_coef,$size_ind_coef,nclust)=0.d0,source($size_C_eqn)=0.d0\n";
		print OUT "\tinteger, save :: charge(nclust)=0,ind_quad_loss($size_ind_coef,0:$ind_quad_loss[0])=0,ind_quad_form($size_ind_coef,0:$ind_quad_form[0])=0\n";
		print OUT "\tinteger, save :: ind_quad_loss_extra($size_ind_coef,0:$ind_quad_loss_extra[0])=0,ind_quad_form_extra($size_ind_coef,0:$ind_quad_form_extra[0])=0\n";
		print OUT "\tinteger, save :: ind_lin_loss($size_ind_coef,0:$ind_lin_loss[0])=0,ind_lin_form($size_ind_coef,0:$ind_lin_form[0])=0,fitted($size_C_eqn,0:$size_C_eqn)=0\n";
        if($l_save_outgoing_clust){
            print OUT "\tinteger, save :: ind_out_clust(nclust,nclust)=0\n";
        }
		print OUT "\tlogical, save :: isconst($size_C_eqn)=.false.\n";
	}
	if($l_jlim){
		print OUT "\tinteger, parameter :: nlim = $nlim\n";
		print OUT "\treal(kind(1.d0)), parameter :: r_lim(nlim) = (/$jlim_sizes_list/)*1.d-9\n";
		print OUT "\tinteger :: l, ij, nmin\n";
		print OUT "\treal(kind(1.d0)) :: j_lim(nlim)";
		if($lloop_j_frac){
			print OUT ", j_lim_frac(nlim,neqn)";
		}
		print OUT "\n";
		print OUT "\treal(kind(1.d0)) :: ri, rj, rk, mi, mj, mk\n";
	}
	if($lloop && ($nmol_types_used>1 || $l_j_in)){
		print OUT "\n";
		print OUT "\t! system size parameters\n";
		if($nmol_types_used>1){
			print OUT "\tif (nclust_inc .eq. 0) then\n";
			print OUT "\t\tcall get_molecule_numbers$append_to_eq_names(nclust_inc,indices)\n";
			print OUT "\t\tcall get_cluster_numbers$append_to_eq_names(clust_from_indices)\n";
			if($disable_nonmonomers){
				print OUT "\t\tcall monomer_indices$append_to_syst_names(n_monomers)\n";
			}
			if($lloop_restrict){
				print OUT "\t\tallocate(K(nclust_inc,nclust_inc))\n";
				if($l_jlim && !$disable_evap){
					print OUT "\t\tallocate(E(nclust_inc,nclust_inc))\n";
				}
			}
			print OUT "\tend if\n";
		}
		if($l_j_in){
			print OUT "\tif (n_j_in .eq. 0) then\n";
			print OUT "\t\tdo i = 1,$nclust_included\n";
			print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mi,ri,i)\n";
			print OUT "\t\t\tif (ri*1.d9 .ge. r_j_in) then\n";
			print OUT "\t\t\t\tn_j_in = i\n";
			print OUT "\t\t\t\twrite(*,*) 'Size for which the input J will be used:'\n";
			print OUT "\t\t\t\twrite(*,*) r_j_in,' nm, ',n_j_in,' molecules'\n";
			print OUT "\t\t\t\texit\n";
			print OUT "\t\t\tend if\n";
			print OUT "\t\tend do\n";
			print OUT "\tend if\n";
		}
	}
	print OUT "\n";
	print OUT "\tif (ipar(3) .eq. 0) then\n";
	print OUT "\t\tipar(3) = 1\n";
	
	if($lloop){

		# The current print-out of the formation rate in the loop mode is a nightmare;
		# it should be re-organized, but meanwhile be careful when you make any modifications
		
		if( $variable_temp){
			print OUT "\t\tcall get_coll$append_to_eq_names($nclust_included,K,coef(1))\n";
		}else{
			print OUT "\t\tcall get_coll$append_to_eq_names($nclust_included,K)\n";
		}
		if($l_jlim && !$disable_evap){
			if($variable_temp){
				print OUT "\t\tcall get_evap$append_to_eq_names($nclust_included,E,K,coef(1))\n";
			}else{
				print OUT "\t\tcall get_evap$append_to_eq_names($nclust_included,E)\n";
			}
		}
		# Add the factor that deals with the permutations for processes involving two similar clusters
		# (For speed, it's added here instead of inside the loop)
		if($disable_nonmonomers && $nmol_types_used>1){
			# If only monomer processes are included, add the factor to all monomer-monomer processes,
			# as processes between different types of monomers will be otherwise counted twice in the loop
			print OUT "\t\tdo i = 1,$nmol_types_used\n";
			print OUT "\t\t\tdo j = 1,$nmol_types_used\n";
			print OUT "\t\t\t\tK(n_monomers(i),n_monomers(j)) = 0.5d0*K(n_monomers(i),n_monomers(j))\n";
			print OUT "\t\t\t\tK(n_monomers(j),n_monomers(i)) = K(n_monomers(i),n_monomers(j))\n";
			print OUT "\t\t\tend do\n";
			print OUT "\t\tend do\n";
		}else{
			print OUT "\t\tdo i = 1,$nclust_included\n";
			print OUT "\t\t\tK(i,i) = 0.5d0*K(i,i)\n";
			print OUT "\t\tend do\n";
		}
		print OUT "\tend if\n\n";
		print OUT "\tj_out = 0.d0\n";
		if($l_jlim){
			print OUT "\tj_lim = 0.d0\n";
			if($lloop_j_frac){
				print OUT "\tj_lim_frac = 0.d0\n";
			}
		}
		if($nmol_types_used==1 && $disable_nonmonomers){
			if($lloop_cs){
				print OUT "\tj_out = j_out+K(nclust-1,1)*c(nclust-1)*c(1)\n";
			}else{
				print OUT "\tj_out = j_out+K(nclust,1)*c(nclust)*c(1)\n";
			}
		}
		if($nmol_types_used>1 || $l_jlim || !$disable_nonmonomers || $lgrowth_for_j_tests){
			# Print a loop over the cluster sizes to go through specific collisions
			if($disable_nonmonomers){
				if($nmol_types_used>1){
					print OUT "\tdo imol = 1,$nmol_types_used\n";
					print OUT "\t\ti = n_monomers(imol)\n";
				}else{
					print OUT "\tdo i = 1,1\n";
				}
			}else{
				if(!$l_j_in){
					print OUT "\tdo i = 1,$nclust_included\n";
				}else{
					print OUT "\tdo i = n_j_in,$nclust_included\n";
					print OUT "\t\t! collisions among clusters taken into account in the distribution\n";
				}
			}
			if($nmol_types_used>1){
				if($l_jlim){
					print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(mi,ri,indices(i,:))\n";
				}
				if($disable_nonmonomers){
					if(!$l_j_in){
						print OUT "\t\tdo j = 1,$nclust_included\n";
					}else{
						print OUT "\t\tdo j = n_j_in,$nclust_included\n";
					}
				}else{
					print OUT "\t\tdo j = i,$nclust_included\n";
				}
				print OUT "\t\t\tij_ind = indices(i,:)+indices(j,:)\n";
				print OUT "\t\t\tif (clust_from_indices($nmol_ranges_ij_ind) .eq. 0) then\n";
				print OUT "\t\t\t\tj_out = j_out+K(j,i)*c(i)*c(j)\n";
				if($lloop_boundary && $l_jlim){
					print OUT "\t\t\telse if (clust_from_indices($nmol_ranges_ij_ind) .eq. -1) then\n";
					print OUT "\t\t\t\tcycle\n";
				}
				print OUT "\t\t\tend if\n";
			}elsif($nmol_types_used==1 && !$disable_nonmonomers){
				print OUT "\t\tdo j = max(i,$n_flux_out-i),nclust\n";
				print OUT "\t\t\tj_out = j_out+K(j,i)*c(i)*c(j)\n";
				print OUT "\t\tend do\n";
			}
			if($l_jlim){
				if($nmol_types_used>1){
					print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mj,rj,indices(j,:))\n";
					print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mk,rk,ij_ind)\n";
				}else{
					print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(mi,ri,i)\n";
					if($disable_nonmonomers){
						print OUT "\t\tdo j = 1,nclust\n";
					}else{
						print OUT "\t\tdo j = i,nclust\n";
					}
					print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mj,rj,j)\n";
					print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mk,rk,i+j)\n";
				}
				print OUT "\t\t\tdo l = 1,nlim\n";
				print OUT "\t\t\t\tif (ri.lt.r_lim(l) .and. rj.lt.r_lim(l) .and. rk.ge.r_lim(l)) then\n";
				print OUT "\t\t\t\t\tj_lim(l) = j_lim(l)+K(j,i)*c(i)*c(j)\n";
				if($lloop_j_frac){
					if($nmol_types_used>1){
						print OUT "\t\t\t\t\tif (sum(indices(j,:)) .lt. sum(indices(i,:))) then\n";
						print OUT "\t\t\t\t\t\tnmin = j\n";
						print OUT "\t\t\t\t\telse\n";
						print OUT "\t\t\t\t\t\tnmin = i\n";
						print OUT "\t\t\t\t\tend if\n";
					}else{
						print OUT "\t\t\t\t\tnmin = min(i,j)\n";
					}				
					print OUT "\t\t\t\t\tj_lim_frac(l,nmin) = j_lim_frac(l,nmin)+K(j,i)*c(i)*c(j)\n";
				}
				if(!$disable_evap){
					print OUT "\t\t\t\t\t$lines{'l_evap'}";
					if($nmol_types_used>1){
						print OUT "\t\t\t\t\t\tij = clust_from_indices($nmol_ranges_ij_ind)\n";
					}else{
						print OUT "\t\t\t\t\t\tij = i+j\n";
					}
					print OUT "\t\t\t\t\t\tj_lim(l) = j_lim(l)-E(j,i)*c(ij)\n";
					if($lloop_j_frac){
						print OUT "\t\t\t\t\t\tj_lim_frac(l,nmin) = j_lim_frac(l,nmin)-E(j,i)*c(ij)\n";
					}
					print OUT "\t\t\t\t\tend if\n";
				}
				print OUT "\t\t\t\tend if\n";
				print OUT "\t\t\tend do\n";
			}
			if($nmol_types_used>1 || $l_jlim){
				print OUT "\t\tend do\n";
			}
			if($l_j_in && !$disable_nonmonomers){
				# Deal with the clusters colliding with a monomer here, since the monomer isn't included in the equation loop
				print OUT "\t\t! monomer collisions\n";
				print OUT "\t\tj = 1\n";
				print OUT "\t\tif (i+j .ge. $n_flux_out) then\n";
				print OUT "\t\t\tj_out = j_out+K(j,i)*c(i)*c(j)\n";
				print OUT "\t\tend if\n";
				if($l_jlim){
					print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(mj,rj,j)\n";
					print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(mk,rk,i+j)\n";
					print OUT "\t\tdo l = 1,nlim\n";
					print OUT "\t\t\tif (ri.lt.r_lim(l) .and. rj.lt.r_lim(l) .and. rk.ge.r_lim(l)) then\n";
					print OUT "\t\t\t\tj_lim(l) = j_lim(l)+K(j,i)*c(i)*c(j)\n";
					if($lloop_j_frac){
						if($nmol_types_used>1){
							print OUT "\t\t\t\tif (sum(indices(j,:)) .lt. sum(indices(i,:))) then\n";
							print OUT "\t\t\t\t\tnmin = j\n";
							print OUT "\t\t\t\telse\n";
							print OUT "\t\t\t\t\tnmin = i\n";
							print OUT "\t\t\t\tend if\n";
						}else{
							print OUT "\t\t\t\tnmin = min(i,j)\n";
						}
						print OUT "\t\t\t\tj_lim_frac(l,nmin) = j_lim_frac(l,nmin)+K(j,i)*c(i)*c(j)\n";
					}
					if(!$disable_evap){
						print OUT "\t\t\t\t$lines{'l_evap'}";
						if($nmol_types_used>1){
							print OUT "\t\t\t\t\t\tij = clust_from_indices($nmol_ranges_ij_ind)\n";
						}else{
							print OUT "\t\t\t\t\tij = i+j\n";
						}
						print OUT "\t\t\t\t\tj_lim(l) = j_lim(l)-E(j,i)*c(ij)\n";
						if($lloop_j_frac){
							print OUT "\t\t\t\t\tj_lim_frac(l,nmin) = j_lim_frac(l,nmin)-E(j,i)*c(ij)\n";
						}
						print OUT "\t\t\t\tend if\n";
					}
					print OUT "\t\t\tend if\n";
					print OUT "\t\tend do\n";
				}
			}
			if($lgrowth_for_j_tests){
				print OUT "\t\t! collisions with the implicit growth compound\n";
				print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,i)\n";
				print OUT "\t\tif (r .ge. $rlim_growth_compound_str) then\n";
				print OUT "\t\t\tj = 2\n";
				print OUT "\t\t\tif (i+j .ge. $n_flux_out) then\n";
				print OUT "\t\t\t\tj_out = j_out+K(i,j)*c(i)*$c_growth_compound_str\n";
				print OUT "\t\t\tend if\n";
				if($l_jlim){
					print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mj,rj,j)\n";
					print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mk,rk,i+j)\n";
					print OUT "\t\t\tdo l = 1,nlim\n";
					print OUT "\t\t\t\tif (ri.lt.r_lim(l) .and. rj.lt.r_lim(l) .and. rk.ge.r_lim(l)) then\n";
					print OUT "\t\t\t\t\tj_lim(l) = j_lim(l)+K(j,i)*c(i)*$c_growth_compound_str\n";
					if($lloop_j_frac){
						print OUT "\t\t\t\t\tnmin = min(i,j)\n";
						print OUT "\t\t\t\t\tj_lim_frac(l,nmin) = j_lim_frac(l,nmin)+K(j,i)*c(i)*$c_growth_compound_str\n";
					}
					print OUT "\t\t\t\tend if\n";
					print OUT "\t\t\tend do\n";
				}
				print OUT "\n";
				print OUT "\t\t\tj = 3\n";
				print OUT "\t\t\tif (i+j .ge. $n_flux_out) then\n";
				print OUT "\t\t\t\tj_out = j_out+K(j,i)*c(i)*$c_growth_compound_str\n";
				print OUT "\t\t\tend if\n";
				if($l_jlim){
					print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mj,rj,j)\n";
					print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mk,rk,i+j)\n";
					print OUT "\t\t\tdo l = 1,nlim\n";
					print OUT "\t\t\t\tif (ri.lt.r_lim(l) .and. rj.lt.r_lim(l) .and. rk.ge.r_lim(l)) then\n";
					print OUT "\t\t\t\t\tj_lim(l) = j_lim(l)+K(j,i)*c(i)*$c_growth_compound_str\n";
					if($lloop_j_frac){
						print OUT "\t\t\t\t\tnmin = min(i,j)\n";
						print OUT "\t\t\t\t\tj_lim_frac(l,nmin) = j_lim_frac(l,nmin)+K(j,i)*c(i)*$c_growth_compound_str\n";
					}
					print OUT "\t\t\t\tend if\n";
					print OUT "\t\t\tend do\n";
				}
				print OUT "\t\tend if\n";
			}
			print OUT "\tend do\n";
		}
		
	}else{
		print OUT "\t\tcall initialize_parameters$append_to_eq_names(coef_quad,coef_lin,ind_quad_loss,ind_quad_form,&\n\t\t\t&ind_lin_loss,ind_lin_form,ind_quad_loss_extra,ind_quad_form_extra,&\n";
        if($l_save_outgoing_clust){
            print OUT "\t\t&\tind_out_clust,&\n";
        }
        print OUT "\t\t&\tsource,isconst,fitted";
		if($l_mcmc_any || $l_variable_parameters){
			print OUT ",coef";
		}
		print OUT ",ipar)\n";
		print OUT "\t\t! cluster charges\n\t\tcharge = (/";
		$line = '';
		$i = 1;
		for($iclus=1;$iclus <= $max_cluster_number;$iclus++){
			if($i==30){
				$line = "$line&\n\t\t\t\t&";
				$i = 0;
			}
			$i += 1;
			if($lneutral_cluster[$iclus]){
				$line = "$line 0,";
			}elsif(($iclus==$n_generic_neg) || $lnegative_cluster[$iclus]){
				$line = "$line-1,";
			}elsif(($iclus==$n_generic_pos) || $lpositive_cluster[$iclus]){
				$line = "$line 1,";
			}else{
				die "\nThe charge of cluster $iclus ($label[$iclus]) is not defined!\n\n";
			}
		}
		$line =~ s/,$//;
		print OUT "$line /)\n";
		print OUT "\tend if\n";
		print OUT "\tj_tot = 0.d0\t\t\t! total formation rate\n";
		print OUT "\tj_by_charge = 0.d0\t\t! contributions of neutrals, negatives, positives and recombinations\n";
		print OUT "\tj_by_cluster = 0.d0\t\t! contributions of different clusters\n";
		print OUT "\tj_all = 0.d0\t\t\t! contributions of different clusters and different charging states\n";
		if($include_generic_neg && $include_generic_pos){
			if($generic_positive_ions_corr ne ''){
				print OUT "\n\t! setting positive charger ion concentration to give charge balance\n";
				print OUT "\tif (c($n_generic_neg)+$generic_positive_ions_corr>0) then\n";
				print OUT "\tc($n_generic_pos) = c($n_generic_neg)+$generic_positive_ions_corr\n";
				print OUT "\telse\n";
				print OUT "\t\tc($n_generic_neg) = -($generic_positive_ions_corr)\n";
				print OUT "\t\tc($n_generic_pos) = 0\n";
				print OUT "\tend if\n\n";
			}elsif($generic_negative_ions_corr ne ''){
				print OUT "\n\t! setting negative charger ion concentration to give charge balance\n";
				print OUT "\tif (c($n_generic_pos)+$generic_negative_ions_corr>0) then\n";
				print OUT "\tc($n_generic_neg) = c($n_generic_pos)+$generic_negative_ions_corr\n";
				print OUT "\telse\n";
				print OUT "\t\tc($n_generic_pos) = -($generic_negative_ions_corr)\n";
				print OUT "\t\tc($n_generic_neg) = 0\n";
				print OUT "\tend if\n\n";
			}elsif($generic_positive_ions ne ''){
				print OUT "\n\t! setting positive charger ion concentration to give charge balance\n";
				print OUT "\tc($n_generic_pos) = $generic_positive_ions\n\n";
			}elsif($generic_negative_ions ne ''){
				print OUT "\n\t! setting negative charger ion concentration to give charge balance\n";
				print OUT "\tc($n_generic_neg) = $generic_negative_ions\n\n";
			}
			if($l_q_neg_mcmc){
				print OUT "\n\t! negative charger ion source term from mcmc coefficient\n";
				print OUT "\tsource($n_generic_neg) = coef(" . ($ncoef_coll+$ncoef_evap+1) . ")\n\n";
			}
			if($l_q_pos_mcmc){
				print OUT "\n\t! positive charger ion source term from mcmc coefficient\n";
				print OUT "\tsource($n_generic_pos) = coef(" . ($ncoef_coll+$ncoef_evap+$l_q_neg_mcmc+1) . ")\n\n";
			}
		}
		if($include_negative_ion_terms || $include_positive_ion_terms){
			print OUT "\tdo j = $n_flux_out, $n_flux_out_max\n";
			print OUT "\t\tdo n = 1, 2*ind_quad_form(j,0)-1, 2 ! loop over all collisions leading out of the system\n";
			if($include_negative_ion_terms && $include_positive_ion_terms){
				print OUT "\t\t\tif ((j .eq. $n_flux_out) .and. (charge(ind_quad_form(j,n)) .eq. 0) .and. (charge(ind_quad_form(j,n+1)) .eq. 0)) then\n";
				print OUT "\t\t\t\ti = 1 ! neutral-neutral collision\n";
				print OUT "\t\t\telseif (j .eq. $n_flux_out_neg) then\n";
				print OUT "\t\t\t\ti = 2 ! negative ion-neutral collision\n";
				print OUT "\t\t\telseif (j .eq. $n_flux_out_pos) then\n";
				print OUT "\t\t\t\ti = 3 ! positive ion-neutral collision\n";
				print OUT "\t\t\telse\n";
				print OUT "\t\t\t\ti = 4 ! negative ion-positive ion recombination\n";
			}elsif($include_negative_ion_terms){
				print OUT "\t\t\tif ((j .eq. $n_flux_out)) then\n";
				print OUT "\t\t\t\ti = 1 ! neutral-neutral collision\n";
				print OUT "\t\t\telse\n";
				print OUT "\t\t\t\ti = 2 ! negative ion-neutral collision\n";
			}else{
				print OUT "\t\t\tif ((j .eq. $n_flux_out)) then\n";
				print OUT "\t\t\t\ti = 1 ! neutral-neutral collision\n";
				print OUT "\t\t\telse\n";
				print OUT "\t\t\t\ti = 3 ! positive ion-neutral collision\n";
			}
			print OUT "\t\t\tend if\n";
			print OUT "\t\t\tj_add = coef_quad(ind_quad_form(j,n),ind_quad_form(j,n+1),j)*c(ind_quad_form(j,n))*c(ind_quad_form(j,n+1))\n";
			print OUT "\t\t\tj_tot = j_tot + j_add\n";
			print OUT "\t\t\tj_by_charge(i) = j_by_charge(i) + j_add\n";
			print OUT "\t\t\tj_by_cluster(ind_quad_form(j,n)) = j_by_cluster(ind_quad_form(j,n)) + j_add\n";
			print OUT "\t\t\tj_by_cluster(ind_quad_form(j,n+1)) = j_by_cluster(ind_quad_form(j,n+1)) + j_add\n";
			print OUT "\t\t\tj_all(ind_quad_form(j,n),i) = j_all(ind_quad_form(j,n),i) + j_add\n";
			print OUT "\t\t\tj_all(ind_quad_form(j,n+1),i) = j_all(ind_quad_form(j,n+1),i) + j_add\n";
			print OUT "\t\tend do\n";
			print OUT "\tend do\n";
		}else{
			print OUT "\tdo n = 1, 2*ind_quad_form($n_flux_out,0)-1, 2 ! loop over all collisions leading out of the system\n";
			print OUT "\t\tj_add = coef_quad(ind_quad_form($n_flux_out,n),ind_quad_form($n_flux_out,n+1),$n_flux_out)*c(ind_quad_form($n_flux_out,n))*c(ind_quad_form($n_flux_out,n+1))\n";
			print OUT "\t\tj_tot = j_tot + j_add\n";
			print OUT "\t\tj_by_charge(1) = j_by_charge(1) + j_add\n";
			print OUT "\t\tj_by_cluster(ind_quad_form($n_flux_out,n)) = j_by_cluster(ind_quad_form($n_flux_out,n)) + j_add\n";
			print OUT "\t\tj_by_cluster(ind_quad_form($n_flux_out,n+1)) = j_by_cluster(ind_quad_form($n_flux_out,n+1)) + j_add\n";
			print OUT "\t\tj_all(ind_quad_form($n_flux_out,n),1) = j_all(ind_quad_form($n_flux_out,n),1) + j_add\n";
			print OUT "\t\tj_all(ind_quad_form($n_flux_out,n+1),1) = j_all(ind_quad_form($n_flux_out,n+1),1) + j_add\n";
			print OUT "\tend do\n";
		}
	}
	print OUT "\nend subroutine formation$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
}

################################################################################
################################################################################
##      8.7 Formation rate for Matlab                                         ##
################################################################################
################################################################################

if(!$lfortran){
	open(JFILE, ">$j_file_name") || die "\nCould not open formation rate file $j_file_name\n\n";
	
	if(!$variable_temp){
		print JFILE "function J = $j_function_name(c,K)\n\n";
		print JFILE "c = c*1e6; % converting from cm^-3 to m^-3\n\n";
		print JFILE "if nargin==1\n";
		print JFILE "\tget_coll$append_to_file_names; % reading collision rates\n";
		print JFILE "end\n";
	}else{
		print JFILE "function J = $j_function_name(c,temperature,K)\n\n";
		print JFILE "c = c*1e6; % converting from cm^-3 to m^-3\n\n";
		print JFILE "if nargin==2\n";
		print JFILE "\tK = get_coll$append_to_file_names(temperature); % reading collision rates\n";
		print JFILE "end\n";
	}
	
	print JFILE "\nJ = ";
	$line_temp = "";
	$lfound = 0;
	for($j=$n_flux_out;$j<=$n_flux_out_max;$j++){
		for($i=1;$i<=2*$ind_quad_form[$j][0];$i+=2){
			$iclus = $ind_quad_form[$j][$i];
			$jclus = $ind_quad_form[$j][$i+1];
			if(exists $coef_quad_form{"$iclus,$jclus,$j"}){
				$line_temp = "$line_temp+" . $coef_quad_form{"$iclus,$jclus,$j"} . "*c($iclus)*c($jclus) ";
				$lfound = 1;
			}else{
				$line_temp = "$line_temp+" . $coef_quad{"$iclus,$jclus,$j"} . "*c($iclus)*c($jclus) ";
				$lfound = 1;
			}
			if(($i+1)==6){
				print JFILE "$line_temp";
				$line_temp = "";
			}elsif(($i+1)%6==0){
				print JFILE "...\n\t$line_temp";
				$line_temp = "";
			}
		}
	}
	if(!$lfound){
		print JFILE "0;";
	}else{
		print JFILE "$line_temp;";
	}
	
	print JFILE "\n\nJ = J*1e-6; % converting from m^-3s^-1 to cm^-3s^-1\n\nend\n";
	close(JFILE);
}

################################################################################
################################################################################
##      8.8 Arrays for collisions, evaporations and losses for Fortran        ##
################################################################################
################################################################################

# First see if some derivatives are not used, i.e. the arrays don't need to be printed out
for($iclus=1;$iclus <= $size_C_out;$iclus++){
	$no_derivative[$iclus]=0;
}
for($icol=0;$icol<=$#no_derivative_clus;$icol++){
	($iclus,$nwaters)=&get_corresponding_dry($no_derivative_clus[$icol]);
	if($iclus eq ''){
		die "Cluster $no_derivative_clus[$icol] for which the derivative should not be printed out does not exist.\n";
	}
	$no_derivative[$iclus]=1;
}

if($lfortran && !$lloop){
	print OUT "subroutine initialize_parameters$append_to_eq_names(coef_quad,coef_lin,ind_quad_loss,ind_quad_form,&\n\t\t\t&ind_lin_loss,ind_lin_form,ind_quad_loss_extra,ind_quad_form_extra,&\n";
    if($l_save_outgoing_clust){
        print OUT "\t\t&\tind_out_clust,&\n";
    }
    print OUT "\t\t&\tsource,isconst,fitted";
	if($l_mcmc_any || $l_variable_parameters){
		print OUT ",coef";
	}
	print OUT ",ipar)\n";
	print OUT "\n\tuse acdc_simulation_setup$append_to_ext_names, only : sources_and_constants$append_to_ext_names\n\n\timplicit none\n";
	print OUT "\tinteger, parameter :: nclust=$max_cluster_number, neqn=$size_C_out\n";
	print OUT "\tlogical :: isconst($size_C_eqn)\n";
	print OUT "\treal(kind(1.d0)) :: coef_quad(nclust,nclust,$size_ind_coef),coef_lin($size_ind_coef,$size_ind_coef,nclust)\n";
	print OUT "\treal(kind(1.d0)) :: source($size_C_eqn)\n";
	print OUT "\tinteger :: ind_quad_loss($size_ind_coef,0:$ind_quad_loss[0]),ind_quad_form($size_ind_coef,0:$ind_quad_form[0]),ind_quad_loss_extra($size_ind_coef,0:$ind_quad_loss_extra[0]),ind_quad_form_extra($size_ind_coef,0:$ind_quad_form_extra[0])\n";
	print OUT "\tinteger :: ind_lin_loss($size_ind_coef,0:$ind_lin_loss[0]),ind_lin_form($size_ind_coef,0:$ind_lin_form[0])\n";
	print OUT "\tinteger :: fitted($size_C_eqn,0:$size_C_eqn)\n";
    if($l_save_outgoing_clust){
        print OUT "\tinteger :: ind_out_clust(nclust,nclust)\n"
    }
	if($l_mcmc_any){
		print OUT "\treal(kind(1.d0)) :: coef($n_mcmc_coefs)\n";
	}elsif($l_variable_parameters){
		print OUT "\treal(kind(1.d0)) :: coef($n_variable_parameters)\n";
	}
	print OUT "\tinteger :: ipar(4)";
    print OUT "\n";
	
	print OUT "\n\tcall sources_and_constants$append_to_ext_names($size_C_eqn,source,isconst,fitted)\n";
	if($include_generic_neg && $include_generic_pos){
		if($generic_positive_ions_corr ne ''){
			print OUT "\n\t! setting positive charger ion concentration to give charge balance\n";
			print OUT "\tisconst($n_generic_pos) = .true.\n\n";
		}elsif($generic_negative_ions_corr ne ''){
			print OUT "\n\t! setting negative charger ion concentration to give charge balance\n";
			print OUT "\tisconst($n_generic_neg) = .true.\n\n";
		}elsif($generic_positive_ions ne ''){
			print OUT "\n\t! setting positive charger ion concentration to give charge balance\n";
			print OUT "\tisconst($n_generic_pos) = .true.\n\n";
		}elsif($generic_negative_ions ne ''){
			print OUT "\n\t! setting negative charger ion concentration to give charge balance\n";
			print OUT "\tisconst($n_generic_neg) = .true.\n\n";
		}
	}
	if($variable_ion_source){
		print OUT "\tisconst($n_generic_neg) = .false.\n";
		print OUT "\tsource($n_generic_neg) = coef(" . ($variable_temp+$variable_cs+1) . ")\n";
		print OUT "\tisconst($n_generic_pos) = .false.\n";
		print OUT "\tsource($n_generic_pos) = coef(" . ($variable_temp+$variable_cs+2) . ")\n";
	}
	print OUT "\n\tind_quad_loss = 0\n\tind_quad_form = 0\n\tind_lin_loss = 0\n\tind_lin_form = 0\n\tind_quad_loss_extra = 0\n\tind_quad_form_extra = 0\n";
    if($l_save_outgoing_clust){
        print OUT "\tind_out_clust = 0\n";
    }
    print OUT "\n";
	print OUT "\t! ind_quad_loss(i,0:2n) = (/n,j1,k1,j2,k2,...,jn,kn/) gives the cluster numbers for all the collisions\n";
	print OUT "\t!  i + j1 -> k1 etc. through which cluster i is lost\n\n";
	print OUT "\t! ind_quad_form(k,0:2n) = (/n,i1,j1,i2,j2,...,in,jn/) gives the cluster numbers for all the collisions\n";
	print OUT "\t!  i1 + j1 -> k etc. through which cluster k is formed\n\n";
	print OUT "\t! ind_lin_loss(k,0:2n) = (/n,i1,j1,i2,j2,...,lossn,lossn/) gives the cluster numbers for all the evaporations\n";
	print OUT "\t!  k -> i1 + j1 etc. and other losses k -> wall etc. through which cluster k is lost\n\n";
	print OUT "\t! ind_lin_form(i,0:2n) = (/n,j1,k1,j2,k2,...,jn,kn/) gives the cluster numbers for all the evaporations\n";
	print OUT "\t!  k1 -> i + j1 etc. through which cluster i is formed\n\n";
	print OUT "\t! ind_quad_loss_extra(i,0:3n) = (/n,j1,k1,c1,...,jn,kn,cn/) gives the cluster numbers and coefficients \n";
	print OUT "\t!  i + j1 -> c1*k1 etc. for additional collision products k (e.g. monomers from the boundary)\n";
	print OUT "\t!  in collisions where cluster i is lost\n\n";
	print OUT "\t! ind_quad_form_extra(k,0:2n) = (/n,i1,j1,c1,...,in,jn,cn/) gives the cluster numbers and coefficients \n";
	print OUT "\t!  i1 + j1 -> c1*k etc. for additional ways of forming k (e.g. as a monomer from the boundary)\n\n";
	
	for($iclus=1;$iclus <= $size_C_out;$iclus++){
        if($iclus > $max_n_flux){
            last;
        }
		if($no_derivative[$iclus]==1){
			print OUT "\n\t! Cluster $iclus: $label[$iclus]\n";
			print OUT "\t! Derivative not used and concentration set to be constant\n";
			print OUT "\tisconst($iclus) = .true.\n";
			next;
		}
		if($ind_quad_loss[$iclus][0]+$ind_quad_form[$iclus][0]+$ind_lin_loss[$iclus][0]+$ind_lin_form[$iclus][0]>0){
			print OUT "\n\t! Cluster $iclus: $label[$iclus]\n";
		}
		if($ind_quad_loss[$iclus][0]>0){
			print OUT "\tind_quad_loss($iclus,0:" . $ind_quad_loss[$iclus][0]*2 . ") = (/ $ind_quad_loss[$iclus][0]";
			$i = 1;
			for($icol=1;$icol <= $ind_quad_loss[$iclus][0];$icol++){
				if($i==$max_terms_per_line){
					print OUT "&\n\t\t\t&";
					$i = 0;
				}
				$i += 1;
				print OUT ", $ind_quad_loss[$iclus][2*$icol-1],$ind_quad_loss[$iclus][2*$icol]";
			}
			print OUT " /)\n";
		}
		if($ind_quad_loss_extra[$iclus][0]>0){
			print OUT "\tind_quad_loss_extra($iclus,0:" . $ind_quad_loss_extra[$iclus][0]*3 . ") = (/ $ind_quad_loss_extra[$iclus][0]";
			$i = 1;
			for($icol=1;$icol <= $ind_quad_loss_extra[$iclus][0];$icol++){
				if($i==$max_terms_per_line){
					print OUT "&\n\t\t\t&";
					$i = 0;
				}
				$i += 1;
				print OUT ", $ind_quad_loss_extra[$iclus][3*$icol-2],$ind_quad_loss_extra[$iclus][3*$icol-1],$ind_quad_loss_extra[$iclus][3*$icol]";
			}
			print OUT " /)\n";
		}
		if($ind_quad_form[$iclus][0]>0){
			print OUT "\tind_quad_form($iclus,0:" . $ind_quad_form[$iclus][0]*2 . ") = (/ $ind_quad_form[$iclus][0]";
			$i = 1;
			for($icol=1;$icol <= $ind_quad_form[$iclus][0];$icol++){
				if($i==$max_terms_per_line){
					print OUT "&\n\t\t\t&";
					$i = 0;
				}
				$i += 1;
				print OUT ", $ind_quad_form[$iclus][2*$icol-1],$ind_quad_form[$iclus][2*$icol]";
			}
			print OUT " /)\n";
		}
		if($ind_quad_form_extra[$iclus][0]>0){
			print OUT "\tind_quad_form_extra($iclus,0:" . $ind_quad_form_extra[$iclus][0]*3 . ") = (/ $ind_quad_form_extra[$iclus][0]";
			$i = 1;
			for($icol=1;$icol <= $ind_quad_form_extra[$iclus][0];$icol++){
				if($i==$max_terms_per_line){
					print OUT "&\n\t\t\t&";
					$i = 0;
				}
				$i += 1;
				print OUT ", $ind_quad_form_extra[$iclus][3*$icol-2],$ind_quad_form_extra[$iclus][3*$icol-1],$ind_quad_form_extra[$iclus][3*$icol]";
			}
			print OUT " /)\n";
		}
		if($ind_lin_loss[$iclus][0]>0){
			print OUT "\tind_lin_loss($iclus,0:" . $ind_lin_loss[$iclus][0]*2 . ") = (/ $ind_lin_loss[$iclus][0]";
			$i = 1;
			for($icol=1;$icol <= $ind_lin_loss[$iclus][0];$icol++){
				if($i==$max_terms_per_line){
					print OUT "&\n\t\t\t&";
					$i = 0;
				}
				$i += 1;
				print OUT ", $ind_lin_loss[$iclus][2*$icol-1],$ind_lin_loss[$iclus][2*$icol]";
			}
			print OUT " /)\n";
		}
		if($ind_lin_form[$iclus][0]>0){
			print OUT "\tind_lin_form($iclus,0:" . $ind_lin_form[$iclus][0]*2 . ") = (/ $ind_lin_form[$iclus][0]";
			$i = 1;
			for($icol=1;$icol <= $ind_lin_form[$iclus][0];$icol++){
				if($i==$max_terms_per_line){
					print OUT "&\n\t\t\t&";
					$i = 0;
				}
				$i += 1;
				print OUT ", $ind_lin_form[$iclus][2*$icol-1],$ind_lin_form[$iclus][2*$icol]";
			}
			print OUT " /)\n";
		}
	}
	for($iclus=$size_C_out+1;$iclus <= $max_n_flux;$iclus++){
		if($ind_quad_form[$iclus][0]>0){
			print OUT "\n\t! $label[$iclus]\n";
			print OUT "\tind_quad_form($iclus,0:" . $ind_quad_form[$iclus][0]*2 . ") = (/ $ind_quad_form[$iclus][0]";
			$i = 1;
			for($icol=1;$icol <= $ind_quad_form[$iclus][0];$icol++){
				if($i==$max_terms_per_line){
					print OUT "&\n\t\t\t&";
					$i = 0;
				}
				$i += 1;
				print OUT ", $ind_quad_form[$iclus][2*$icol-1],$ind_quad_form[$iclus][2*$icol]";
			}
			print OUT " /)\n";
		}
	}
    if($l_save_outgoing_clust){
        print OUT "\n\t! Index of the outgrowing cluster for all collisions out\n";
        print OUT "\tcall get_ind_out_clust$append_to_eq_names(ind_out_clust)\n";
    }
	print OUT "\n\tcall get_rate_coefs$append_to_eq_names(coef_quad,coef_lin";
	if($l_mcmc_any || $l_variable_parameters){
		print OUT ",coef";
	}
	print OUT ")\n";
	print OUT "\nend subroutine initialize_parameters$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
	
    if($l_save_outgoing_clust){
        print OUT "subroutine get_ind_out_clust$append_to_eq_names(ind_out_clust)\n";
        print OUT "\timplicit none\n";
        print OUT "\tinteger :: ind_out_clust($max_cluster_number,$max_cluster_number)\n\n";
        print OUT "\tind_out_clust = 0\n\n";
        for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
            for($jclus=$iclus;$jclus<=$max_cluster_number;$jclus++){
                if(defined $ind_out_clust[$iclus][$jclus]){
                    print OUT "\tind_out_clust($iclus,$jclus) = $ind_out_clust[$iclus][$jclus]\n";
                    print OUT "\tind_out_clust($jclus,$iclus) = $ind_out_clust[$iclus][$jclus]\n";
                }
            }
        }
        print OUT "\nend subroutine get_ind_out_clust$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
    }
    
	# Figuring out the input/output parameters of get_fcr -- these are used several times
	# These are used in the subroutine call ...
	$parameters_in_get_fcr_1 = '';
	$parameters_in_get_fcr_2 = '';
	# ... and these are for variable declarations
	$parameters_in_get_fcr_3 = '';
	$parameters_in_get_fcr_4 = '';
	if($include_ion_terms){
		if(!$disable_coag_sinks){
			$parameters_in_get_fcr_1 = "fcs";
			$parameters_in_get_fcr_3 = "fcs";
		}
		if(!$disable_wall_terms && !$l_wl_mcmc){
			if($parameters_in_get_fcr_1 ne ''){
				$parameters_in_get_fcr_1 = "$parameters_in_get_fcr_1,fwl";
				$parameters_in_get_fcr_3 = "$parameters_in_get_fcr_3,fwl";
			}else{
				$parameters_in_get_fcr_1 = "fwl";
				$parameters_in_get_fcr_3 = "fwl";
			}
		}
		$parameters_in_get_fcr_2 = $parameters_in_get_fcr_1;
		$parameters_in_get_fcr_4 = $parameters_in_get_fcr_3;
	}

	print OUT "subroutine get_rate_coefs$append_to_eq_names(coef_quad,coef_lin";
	if($l_mcmc_any || $l_variable_parameters){
		print OUT ",coef";
	}
	print OUT ")\n";
	print OUT "\timplicit none\n";
	print OUT "\treal(kind(1.d0)) :: coef_quad($max_cluster_number,$max_cluster_number,$size_ind_coef),coef_lin($size_ind_coef,$size_ind_coef,$max_cluster_number)\n";
	print OUT "\treal(kind(1.d0)) :: K($max_cluster_number,$max_cluster_number),E($max_cluster_number,$max_cluster_number)";
	if(!$disable_coag_sinks){
		if($one_cs_for_all){
			print OUT ",cs";
		}else{
			print OUT ",cs($max_cluster_number)";
		}
	}
	if(!$disable_wall_terms){
		if($one_wl_for_all){
			print OUT ",wl";
		}else{
			print OUT ",wl($max_cluster_number)";
		}
	}
	if(!$disable_dilution){
		print OUT ",dil";
	}
    if(!$disable_input_sink){
        print OUT ",insink($max_cluster_number)";
	}
	if($parameters_in_get_fcr_3 ne ''){
		print OUT ",$parameters_in_get_fcr_3";
	}
	print OUT "\n";
	if($l_mcmc_any){
		print OUT "\treal(kind(1.d0)) :: coef($n_mcmc_coefs)\n";
	}elsif($l_variable_parameters){
		print OUT "\treal(kind(1.d0)) :: coef($n_variable_parameters)\n";
	}

	print OUT "\n\tcoef_quad = 0.d0\n\tcoef_lin = 0.d0\n";

	if($l_mcmc_any){
		print OUT "\tcall get_coll$append_to_eq_names(K,coef)\n";
	}elsif( $variable_temp){
		print OUT "\tcall get_coll$append_to_eq_names(K,coef(1))\n";
	}else{
		print OUT "\tcall get_coll$append_to_eq_names(K)\n";
	}

	if($parameters_in_get_fcr_1 ne ''){
		print OUT "\tcall get_fcr$append_to_eq_names($parameters_in_get_fcr_1)\n";
	}

	if(!$disable_evap){
		if($l_mcmc_any){
			print OUT "\tcall get_evap$append_to_eq_names(E,coef)\n";
		}elsif($variable_temp){
			print OUT "\tcall get_evap$append_to_eq_names(E,K,coef(1))\n";
		}else{
			print OUT "\tcall get_evap$append_to_eq_names(E)\n";
		}
	}
	if($l_use_get_losses){
		$line = '';
		if(!$disable_coag_sinks && (!$one_cs_for_all || !$variable_cs)){
			$line = 'cs';
		}
		if(!$disable_wall_terms || ($l_mcmc_any && $ncoef_wl>0)){
			if($line ne ''){
				$line = "$line,wl";
			}else{
				$line = 'wl';
			}
		}
		if(!$disable_dilution){
			if($line ne ''){
				$line = "$line,dil";
			}else{
				$line = 'dil';
			}
		}
        if(!$disable_input_sink){
			if($line ne ''){
				$line = "$line,insink";
			}else{
				$line = 'insink';
			}
		}
        if(!$disable_coag_sinks && $coag_terms =~ m/^external$/i){
            if($variable_temp){
                $line = "$line,coef(1)";
            }else{
                $line = "$line,$temperature";
                if($temperature !~ m/\./){
                    $line .= ".";
                }
                $line .= "d0";
            }
        }
		print OUT "\tcall get_losses$append_to_eq_names($line)\n";
	}
	if($variable_cs){
		if($one_cs_for_all){
			print OUT "\tcs = coef(" . ($variable_temp+1) . ")\n";
		}else{
			print OUT "\tcs = coef(" . ($variable_temp+1) . ")*cs\n";
		}
	}
	if($l_wl_mcmc && $ncoef_wl==1){
		print OUT "\twl = coef($n_mcmc_coefs)\t\t\t\t! wall loss\n";
	}
	print OUT "\n";
	for($iclus=1;$iclus <= $max_n_flux;$iclus++){
		$line = '';
		for($jclus=1;$jclus <= $iclus;$jclus++){
			for($kclus=$max_n_flux;$kclus >=1 ;$kclus-=1){
				if(exists $coef_quad{"$iclus,$jclus,$kclus"}){
					if(exists $l_quad_bound{"$iclus,$jclus,$kclus"}){
						$line = $line . "\tcoef_quad($iclus,$jclus,$kclus) = " . $coef_quad{"$iclus,$jclus,$kclus"} . "\t! $label[$iclus] + $label[$jclus] -> boundary -> $label[$kclus]\n";
					}elsif($use_coag_to_outgoing && $kclus==$n_flux_out){
						$line = $line . "\tcoef_quad($iclus,$jclus,$kclus) = " . $coef_quad{"$iclus,$jclus,$kclus"} . "\t! $label[$iclus] + $label[$jclus] -> out -> cs_cluster\n";
					}elsif($use_coag_to_outgoing && $kclus==$n_flux_out_neg){
						$line = $line . "\tcoef_quad($iclus,$jclus,$kclus) = " . $coef_quad{"$iclus,$jclus,$kclus"} . "\t! $label[$iclus] + $label[$jclus] -> out -> cs_cluster_neg\n";
					}elsif($use_coag_to_outgoing && $kclus==$n_flux_out_pos){
						$line = $line . "\tcoef_quad($iclus,$jclus,$kclus) = " . $coef_quad{"$iclus,$jclus,$kclus"} . "\t! $label[$iclus] + $label[$jclus] -> out -> cs_cluster_pos\n";
					}else{
						$line = $line . "\tcoef_quad($iclus,$jclus,$kclus) = " . $coef_quad{"$iclus,$jclus,$kclus"} . "\t! $label[$iclus] + $label[$jclus] -> $label[$kclus]\n";
					}
					if($iclus != $jclus){
						$line = $line . "\tcoef_quad($jclus,$iclus,$kclus) = " . $coef_quad{"$jclus,$iclus,$kclus"} . "\n";
					}
				}
				if(exists $coef_lin{"$iclus,$jclus,$kclus"}){
					if($iclus > $max_cluster_number){
						$line = $line . "\tcoef_lin($iclus,$jclus,$kclus) = " . $coef_lin{"$iclus,$jclus,$kclus"} . "\t! $label[$kclus] -> $label[$iclus]\n";
					}else{
						$line = $line . "\tcoef_lin($iclus,$jclus,$kclus) = " . $coef_lin{"$iclus,$jclus,$kclus"} . "\t! $label[$kclus] -> $label[$iclus] + $label[$jclus]\n";
					}
					if($iclus != $jclus){
						$line = $line . "\tcoef_lin($jclus,$iclus,$kclus) = " . $coef_lin{"$jclus,$iclus,$kclus"} . "\n";
					}
				}
			}
		}
		if($line ne ''){
			print OUT "\n$line";
		}
	}
	print OUT "\nend subroutine get_rate_coefs$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
}	

################################################################################
################################################################################
##      8.9 Masses, radii and molecular content for the loop version
################################################################################
################################################################################

if($lloop){
	if($nmol_types_used>1){
		print OUT "subroutine get_masses_and_radii$append_to_eq_names(m,r,i_ind)\n";
	}else{
		print OUT "subroutine get_masses_and_radii$append_to_eq_names(m,r,i)\n";
	}
	print OUT "\timplicit none\n";
    # Clumsy to have these hard-coded here...
	print OUT "\treal(kind(1.d0)), parameter :: u2kg = 1.660538782d-27, kB=1.3806504d-23, pi=4.d0*atan(1.d0)\n";
	
	$str_temp = '';
	$str_temp2 = '';
	$string1 = '';
	$string2 = '';
	$i = 0;
	$j = 0;
	for($imol=0;$imol<$nmol_types;$imol++){
		if($n_max_type[$imol]>0){
			$i ++;
			$j ++;
			$temp_val = sprintf('%.14e',$mass[$imol]/$mass_conv);
			$temp_val =~ s/e/d/g;
			$str_temp .= "\treal(kind(1.d0)), parameter :: m$i = $temp_val\t\t! in g/mol\n";
			$temp_val = sprintf('%.14e',$mass[$imol]/$density[$imol]);
			$temp_val =~ s/e/d/g;
			$str_temp2 .= "\treal(kind(1.d0)), parameter :: monvol$i = $temp_val\t\t! in m^3\n";
			$string1 .= "real(i_ind($i),kind=kind(1.d0))*m$i+";
			$string2 .= "real(i_ind($i),kind=kind(1.d0))*monvol$i+";
			if($j==2 && $imol<$nmol_types-1){
				$j = 0;
				$string1 .= "&\n\t\t&";
				$string2 .= "&\n\t\t&";
			}
		}
	}
	print OUT "$str_temp";
	print OUT "$str_temp2";
	print OUT "\treal(kind(1.d0)) :: r, m\n";
	if($nmol_types_used>1){
		print OUT "\tinteger :: i_ind($nmol_types_used)\n\n";
		$string1 =~ s/\+$//;
		$string2 =~ s/\+$//;
		$string1 = "($string1)";
		$string2 = "($string2)";
	}else{
		print OUT "\tinteger :: i\n\n";
		$string1 = "real(i,kind=kind(1.d0))*m1";
		$string2 = "real(i,kind=kind(1.d0))*monvol1";
	}
	print OUT "\tm = $string1\n";
	print OUT "\tr = (3.d0/4.d0/pi*$string2)**(1.d0/3.d0)\n\n";
	print OUT "\nend subroutine get_masses_and_radii$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
	
	if($nmol_types_used>1){
		print OUT "subroutine get_molecule_numbers$append_to_eq_names(nclust_inc,indices)\n";
		print OUT "\timplicit none\n";
		print OUT "\tinteger, parameter :: nclust = $max_cluster_number\n";
		print OUT "\tinteger :: n, $nmol_ranges_ind, nclust_inc, indices(nclust,$nmol_types_used), clust_from_indices($nmol_comp_list)\n\n";
		
		print OUT "\tnclust_inc = 0\n";
		print OUT "\tindices = 0\n\n";
		print OUT "\tcall get_cluster_numbers$append_to_eq_names(clust_from_indices)\n\n";
		print OUT "\tn = 0\n";
		
		$str_temp = "\t";
		$str_temp2 = '';
		# Printing loops over all molecule numbers
		for($imol=1;$imol<=$nmol_types_used;$imol++){
			# If there are many molecule types, the molecule number loops start from 0
			print OUT $str_temp."do i$imol = 0,$nmol_ranges_array[$imol]\n";
			$str_temp2 = $str_temp."end do\n".$str_temp2;
			$str_temp .= "\t";
		}
		print OUT $str_temp."if (clust_from_indices($nmol_ranges_ind) .gt. 0) then\n";
		$str_temp2 = $str_temp."end if\n".$str_temp2;
		$str_temp .= "\t";
		print OUT $str_temp."n = n+1\n";
		print OUT $str_temp."indices(clust_from_indices($nmol_ranges_ind),:) = (/$nmol_ranges_ind/)\n";
		print OUT $str_temp2;
		print OUT "\n\tnclust_inc = n\n";
		
		print OUT "\nend subroutine get_molecule_numbers$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
		
		print OUT "subroutine get_cluster_numbers$append_to_eq_names(clust_from_indices)\n";
		if($lloop_restrict){
			print OUT "use restriction_criteria$append_to_ext_names\n";
			print "\n---------------------------------------------------------\n";
			print "\tYou will need the module restriction_criteria$append_to_ext_names\n\tin order to compile and run the code.\n";
			print "---------------------------------------------------------\n\n";
		}
		print OUT "\timplicit none\n";
		if($lloop_cs && $lloop_restrict){
			print OUT "\tinteger, parameter :: ij_ind_cs($nmol_types_used) = (/$nmol_cs_list/)\n";
			print OUT "\tlogical :: lfound\n";
		}
		print OUT "\tinteger :: n, $nmol_ranges_ind, ij_ind($nmol_types_used), clust_from_indices($nmol_comp_list)";
		if($lloop_restrict){
			print OUT ", valid";
		}
		print OUT "\n\n";
		print OUT "\tclust_from_indices = 0\n";
		if($lloop_cs && $lloop_restrict){
			print OUT "\tlfound = .false.\n";
		}
		print OUT "\n\tn = 0\n";
		
		$str_temp = "\t";
		$str_temp2 = '';
		# Printing loops over all molecule numbers
		for($imol=1;$imol<=$nmol_types_used;$imol++){
			# If there are many molecule types, the molecule number loops start from 0 ...
			if(!$lloop_boundary){
				print OUT $str_temp."do i$imol = 0,".$nmol_ranges_array[$imol]."\n";
			}else{
				# Loop over all collision products, as some of them may not be valid
				print OUT $str_temp."do i$imol = 0,".(2*$nmol_ranges_array[$imol])."\n";
			}
			$str_temp2 = $str_temp."end do\n".$str_temp2;
			$str_temp .= "\t";
		}
		# ... but they can't all be 0 ...
		$string = $nmol_ranges_ind;
		$string =~ s/,\s*/\+/g;
		print OUT $str_temp."if ($string>0) then\n";
		$str_temp2 = $str_temp."end if\n".$str_temp2;
		$str_temp .= "\t";
		$string = "";
		if($lloop_restrict){
			print OUT $str_temp."call check_validity$append_to_ext_names((/$nmol_ranges_ind/),valid)\n";
			print OUT $str_temp."if (valid .eq. 1) then\n";
			$string = "\t";
		}
		print OUT $str_temp.$string."n = n+1\n";
		print OUT $str_temp.$string."clust_from_indices($nmol_ranges_ind) = n\n";
		if($lloop_restrict){
			if($lloop_cs){
				print OUT $str_temp."\tif (all((/$nmol_ranges_ind/) .eq. ij_ind_cs)) then\n";
				print OUT $str_temp."\t\tlfound = .true.\n";
				print OUT $str_temp."\tend if\n";
			}
			print OUT $str_temp."else\n";
			print OUT $str_temp."\tclust_from_indices($nmol_ranges_ind) = valid\n";
			print OUT $str_temp."end if\n";
		}
		print OUT $str_temp2;
		if($lloop_cs && $lloop_restrict){
			print OUT "\t! sink cluster, if it's not yet included in the set\n";
			print OUT "\tif (.not. lfound) then\n";
			print OUT "\t\tn = n+1\n";
			print OUT "\t\tij_ind = ij_ind_cs\n";
			print OUT "\t\tclust_from_indices($nmol_ranges_ij_ind) = n\n";
			print OUT "\tend if\n";
		}

		print OUT "\nend subroutine get_cluster_numbers$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";

	}
}


################################################################################
################################################################################
##   9. Loss coefficients                                                     ##
################################################################################
################################################################################

if($lfortran){
	if($l_use_get_losses){
		$lines{'inp'} = '';
		$lines{'def'} = '';
		if(!$disable_coag_sinks){
			if(!$one_cs_for_all){
				$lines{'inp'} = 'cs';
				if($lloop){
					$lines{'def'} = "cs(nrates)";
				}else{
					$lines{'def'} = "cs($max_cluster_number)";
				}
			}elsif(!$variable_cs){
				$lines{'inp'} = 'cs';
				$lines{'def'} = "cs";
			}
		}
		if(!$disable_wall_terms || ($l_mcmc_any && $ncoef_wl>0)){
			if($lines{'inp'} ne ''){
				$lines{'inp'} .= ",";
				$lines{'def'} .= ",";
			}
			$lines{'inp'} .= 'wl';
			if($one_wl_for_all){
				$lines{'def'} .= "wl";
			}else{
				if($lloop){
					$lines{'def'} .= "wl(nrates)";
				}else{
					$lines{'def'} .= "wl($max_cluster_number)";
				}
			}
		}
		if(!$disable_dilution){
			if($lines{'inp'} ne ''){
				$lines{'inp'} .= ",";
				$lines{'def'} .= ",";
			}
			$lines{'inp'} .= 'dil';
			$lines{'def'} .= 'dil';
		}
        if(!$disable_input_sink){
            if($lines{'inp'} ne ''){
				$lines{'inp'} .= ",";
				$lines{'def'} .= ",";
			}
            $lines{'inp'} .= 'insink';
            if($lloop){
                $lines{'def'} .= "insink(nrates)";
            }else{
                $lines{'def'} .= "insink($max_cluster_number)";
            }
		}
        if(!$disable_coag_sinks && $coag_terms =~ m/^external$/i){
            $lines{'inp'} .= ",temperature";
            $lines{'def'} .= ",temperature";
        }
        $str_temp = "";
        if(!$disable_input_sink && $module_insink ne ''){
            $str_temp = "\n\tuse $module_insink, only : $routine_insink\n";
        }
		if(!$lloop){
			print OUT "subroutine get_losses$append_to_eq_names($lines{'inp'})\n";
            if(!$disable_coag_sinks && $coag_terms =~ m/^external$/i){
                print OUT "\n\tuse acdc_simulation_setup$append_to_ext_names, only : get_scav_parameters$append_to_ext_names\n";
            }
            print OUT $str_temp;
			print OUT "\n\timplicit none\n\treal(kind(1.d0)) :: $lines{'def'}\n\n";
		}else{
			print OUT "subroutine get_losses$append_to_eq_names(nrates,loss";
			if($variable_cs){
				print OUT ",coef";
			}
			print OUT ")\n";
			if(!$disable_coag_sinks && $coag_terms =~ m/^bg_loss$/i){
				# Get cbg from a module by default
				#if($lloop_j_tests){
				print OUT "\n\tuse shared_input, only : cbg => bg_concentration\n";
				print "\nUsing module shared_input in the get_losses subroutine to get cbg\n";
				#}
			}
            print OUT $str_temp;
			print OUT "\n\timplicit none\n\treal(kind(1.d0)) :: $lines{'def'}, loss";
			if((!$disable_coag_sinks && !$one_cs_for_all) || ((!$disable_wall_terms || ($l_mcmc_any && $ncoef_wl>0)) && !$one_wl_for_all)){
				print OUT "(nrates), m, r";
				if(!$disable_wall_terms && ($wall_terms =~ m/^cloud4_JK$/i || $wall_terms =~ m/^cloud4_AK$/i)){
					print OUT ", d, sc";
				}
				if(!$disable_coag_sinks){
					if($coag_terms =~ m/^exp_loss$/i){
						print OUT ", r_ref";
					}elsif($coag_terms =~ m/^bg_loss$/i){
						#if($lloop_j_tests){
							print OUT ", vth, D, mbg, rbg, vthbg, Dbg, Kn";
						#}else{
							#print OUT ", vth, D, mbg, rbg, vthbg, Dbg, cbg, Kn";
						#}
					}
				}
			}
			if($variable_cs){
				print OUT ", coef($n_variable_parameters)";
			}
			print OUT "\n";
			print OUT "\tinteger, parameter :: nclust = $max_cluster_number\n";
			print OUT "\tinteger :: nrates, i\n";
			if($nmol_types_used>1){
				print OUT "\tinteger, save :: nclust_inc=0, indices(nclust,$nmol_types_used)";
				if($#cs_only>=0 || $#insink_only>=0){
					print OUT ", clust_from_indices($nmol_comp_list)";
				}
				print OUT "\n\n";
				print OUT "\tif (nclust_inc .eq. 0) then\n";
				print OUT "\t\tcall get_molecule_numbers$append_to_eq_names(nclust_inc,indices)\n";
				if($#cs_only>=0 || $#insink_only>=0){
					print OUT "\t\tcall get_cluster_numbers$append_to_eq_names(clust_from_indices)\n";
				}
				print OUT "\tend if\n";
			}
			print OUT "\n";
		}
		if(!$disable_dilution){
			print OUT "\tdil = $dil_str\n\n";
		}
	}
}else{
	open(CS, ">get_cs$append_to_file_names.m");
	open(WL, ">get_wl$append_to_file_names.m");
}

################################################################################
################################################################################
##      9.1 Coagulation sink                                                  ##
################################################################################
################################################################################

if(! $lfortran){
	print CS "% Coagulation sink terms\n\n";
	if($include_ion_terms){
		print CS "% enhancement factor for ions\nfcs = $fcs;\n\n";
	}
}
if(!$disable_coag_sinks){
	if($lfortran && $l_use_get_losses){
		print OUT "\t! coagulation sink\n\n";
		if($variable_cs){
			if($one_cs_for_all){
				print OUT "\t! variable cs: the value will be given as input\n\n";
			}else{
				print OUT "\t! variable cs: the following values only give the size dependence of the sink,\n";
				print OUT "\t! and will be multiplied by the size-independent factor given as input\n\n";
			}
		}
	}
	# array for the coagulation loss coefficients of the hydrates
	@cs_coef_hydr=();

################################################################################
################################################################################
##         9.11 Coagulation sink parameterizations                            ##
################################################################################
################################################################################

################################################################################
################################################################################
##            9.111 Size-dependent sink of the form A*(d/dref)^B,             ##
##                  where d is the diameter                                   ##
################################################################################
################################################################################
	
	if($coag_terms =~ m/^exp_loss$/i){
		
		if(!$lloop){
            
			# Find the reference size
            if($exp_loss_ref_size ne ''){
                $r1=$exp_loss_ref_size;
			}elsif($exp_loss_ref_cluster ne ''){
				($iclus,$nwaters)=&get_corresponding_dry($exp_loss_ref_cluster);
				if($iclus ne ''){
					$r1=$clust_radius[$iclus][$nwaters];
				}else{
					die "\nCan't calculate loss coefficients relative to $exp_loss_ref_cluster, if you don't have it in the system\n\n";
				}
			}else{
				# Use the monomer (the default monomer if there are several monomers) as reference cluster
	
				# find the monomer(s)
				$lfound=0;
				$lfound_several=0;
				$lfound_default=0;
				for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
					if($lmonomer[$iclus]){
						if($lfound==1){
							$lfound_several=1;
						}
						$lfound=1;
						$radius=$clust_radius[$iclus][0];
						if($label[$iclus] eq "1$default_monomer"){
							$lfound_default=1;
							$r1=$radius;
						}
					}
				}
				if($lfound==0){
					die "\nCan't calculate loss coefficients relative to that of the monomer, if you don't have monomers in the system\n\n";
				}elsif($lfound_several==0){
					$r1=$radius;
				}elsif($lfound_several==1 && $lfound_default==0){
					die "\nDid not find the default monomer $default_monomer among several monomer species for calculating the loss coefficients -> you need to specify the reference cluster as eg. --exp_loss_ref_cluster $label[1]\n";
				}
			}
	
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				# loss coefficients for the dry cluster and possible hydrates
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						if($ihydr==0){
							$temp_label=$label[$iclus];
						}else{
							$temp_label=$label[$iclus].$ihydr.$name_water;
						}
						$radius=$clust_radius[$iclus][$ihydr];

						# Coagulation loss of the form A*(d/dref)^B
						$cs_term_temp = ($radius/$r1)**$exp_loss_exponent;
						if(!$variable_cs){
							# If the sink is not varied, include the reference loss rate in it
							$cs_term_temp *= $exp_loss_coefficient;
						}
						$cs_coef_hydr[$iclus][$ihydr] = $cs_term_temp;
					}
				}
			}
            
		}else{
            
			$exp_loss_coefficient = sprintf('%.14e',$exp_loss_coefficient);
			$exp_loss_coefficient =~ s/e/d/;
			$exp_loss_exponent = sprintf('%.14e',$exp_loss_exponent);
			if(!&is_pos_number($exp_loss_exponent)){
				$exp_loss_exponent = "($exp_loss_exponent)";
			}
			$exp_loss_exponent =~ s/e/d/;
			$cs_coef_hydr[0][0] = "\t\tcs(i) = ";
			if(!$variable_cs){
				$cs_coef_hydr[0][0] .= $exp_loss_coefficient."*";
			}
			$cs_coef_hydr[0][0] .= "(r/r_ref)**$exp_loss_exponent\n";
			
			# Find the reference size
			if($exp_loss_ref_size ne ''){
                $exp_loss_ref_size = sprintf('%.14e',$exp_loss_ref_size);
                $exp_loss_ref_size =~ s/e/d/;
                print OUT "\t! reference radius given as input\n";
                print OUT "\tr_ref = $exp_loss_ref_size\n\n";
			}elsif($exp_loss_ref_cluster ne ''){
				($string1,$string2) = &determine_cluster_composition($exp_loss_ref_cluster);
				@temp_array=@$string1;
				$valid = 1;
				if($string2 ne '' || sum(@temp_array)>sum(@temp_array[@mol_types_used[1..$nmol_types_used]])){
					# cluster contains molecule types not included in the system
					$valid = 0;
				}
				if(!$valid){
					die "Loss term reference cluster $exp_loss_ref_cluster is not a valid cluster\n";
				}
				if($nmol_types_used>1){
					$i = "(/".join(',',@temp_array[@mol_types_used[1..$nmol_types_used]])."/)";
				}else{
					$imol = 1;
					$i = $temp_array[$mol_types_used[$imol]];
				}
				print OUT "\t! reference radius corresponding to $exp_loss_ref_cluster\n";
			}elsif($nmol_types_used==1){
				# Use the monomer as reference cluster
				$i = 1;
				print OUT "\t! reference radius corresponding to 1$molecule_name[$mol_types_used[1]]\n";
			}else{
				# Use the default monomer as reference cluster
				$lfound_default=0;
				for($imol=1;$imol<=$nmol_types_used;$imol++){
					if($molecule_name[$mol_types_used[$imol]] eq $default_monomer){
						$lfound_default = 1;
						@temp_array = (0) x $nmol_types_used;
						$temp_array[$imol-1] = 1;
						$i = "(/".join(',',@temp_array)."/)";
					}
				}
				if($lfound_default==0){
					die "\nDid not find the default monomer $default_monomer among several monomer species for calculating the loss coefficients -> you need to specify the reference cluster as eg. --exp_loss_ref_cluster 1$molecule_name[$mol_types_used[1]]\n";
				}
				print OUT "\t! reference radius corresponding to 1$default_monomer\n";
			}
            if($exp_loss_ref_size eq ''){
                print OUT "\tcall get_masses_and_radii$append_to_eq_names(m,r_ref,$i)\n\n";
            }

		}

################################################################################		
################################################################################		
##            9.112 Size-dependent sink based on a constant concentration     ##
##                  and size of background particles                          ##
################################################################################
################################################################################

	}elsif($coag_terms =~ m/^bg_loss$/i){
		# Loss calculated as the frequency at which the clusters collide with
		# background particles that have constant concentration, diameter and density
		
		if($variable_temp){
			die "\nVariable temperature not implemented for the bg_loss option.\n\n";
		}
		
		$air_viscosity = 2.5277e-7*$temperature**0.75302; # from DMAN
		# mean free path of air, assuming standard pressure
		$temp_val = 2*$air_viscosity/(101325*sqrt(8*0.0289/($pi*$Na*$boltz*$temperature)));
		# S&P Eq. 9.73
		$temp_val2 = $boltz*$temperature/(3*$pi*$air_viscosity);
		# factor for calculating particle velocity
		$temp_val3 = 8*$boltz*$temperature/$pi;
		
		# properties of the background particles
		$mass2=$bg_density*$pi/6*$bg_diameter**3;
		$r2=$bg_diameter/2;
		$Diff2 = $temp_val2/(2*$r2)*((5+4*($temp_val/$r2)+6*($temp_val/$r2)**2+18*($temp_val/$r2)**3)/(5-($temp_val/$r2)+(8+$pi)*($temp_val/$r2)**2));
		$c2 = sqrt($temp_val3/$mass2);

		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				# loss coefficients for the dry cluster and possible hydrates
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						$mass1=$clust_mass[$iclus][$ihydr];
						$r1=$clust_radius[$iclus][$ihydr];
						# Use the parameterization by Dahneke (1983) for the collision coefficients
						# (see the 'Dahneke' option of the loop mode)
						$Diff1 = $temp_val2/(2*$r1)*((5+4*($temp_val/$r1)+6*($temp_val/$r1)**2+18*($temp_val/$r1)**3)/(5-($temp_val/$r1)+(8+$pi)*($temp_val/$r1)**2));
						$c1 = sqrt($temp_val3/$mass1);
						$Kn = 2*($Diff1+$Diff2)/(sqrt($c1**2+$c2**2)*($r1+$r2));
						$cs_term_temp = 4*$pi*($r1+$r2)*($Diff1+$Diff2)*(1+$Kn)/(1+2*$Kn*(1+$Kn));
						if(!$variable_cs){
							# If the sink is not varied, include the bg concentration in it
							$cs_term_temp *= $bg_concentration;
						}
						$cs_coef_hydr[$iclus][$ihydr] = $cs_term_temp;
					}
				}
			}
		}else{
			# print out the mass and radius of the background particles
			$string1 = sprintf('%.14e',$mass2/$mass_conv); # kg -> g/mol, because the masses in get_masses_and_radii of the loop version are g/mol
			$string1 =~ s/e/d/;
			print OUT "\tmbg = $string1\n";
			$string1 = sprintf('%.14e',$r2);
			$string1 =~ s/e/d/;
			print OUT "\trbg = $string1\n";
			#if(!$lloop_j_tests){
				#$string1 = sprintf('%.14e',$bg_concentration);
				#$string1 =~ s/e/d/;
				#print OUT "\tcbg = $string1\n";
			#}
		
			$string1 = sprintf('%.14e',$temp_val);
			$string1 =~ s/e/d/;
			$string2 = sprintf('%.14e',$temp_val2);
			$string2 =~ s/e/d/;
			$string3 = sprintf('%.14e',$temp_val3/$mass_conv); # g/mol -> kg
			$string3 =~ s/e/d/;
			$string4 = sprintf('%.14e',$pi);
			$string4 =~ s/e/d/;
			print OUT "\tDbg = $string2/(2.d0*rbg)*((5.d0+4.d0*($string1/rbg)+&\n\t\t\t\t& 6.d0*($string1/rbg)**2.d0+18.d0*($string1/rbg)**3)/&\n\t\t\t\t& (5.d0-($string1/rbg)+(8.d0+$string4)*($string1/rbg)**2.d0))\n";
			print OUT "\tvthbg = sqrt($string3/mbg)\n\n";
				
			$cs_coef_hydr[0][0] = "";
				
			# For comparisons with DMAN/TOMAS, coefficients for collisions involving an acid or ammonia monomer are calculated in a different way
			# -> uncomment the following block if you want to use this feature
			# if('A' ~~ @molecule_name[@mol_types_used[1..$nmol_types_used]] || 'N' ~~ @molecule_name[@mol_types_used[1..$nmol_types_used]]){
				# print "Applying the DMAN condensation coefficients to the loss of monomers A and N.\n\n";					
				# if($nmol_types_used>1){
					# die "Add this if you need it; don't have time to fix these stupidities now.\n";
				# }else{
					# $cs_coef_hydr[0][0] .= "\t\tif(i .eq. 1) then\n";
					# # gas diffusivity in air from gasdiff.f, assuming standard pressure
					# $str_temp = sprintf('%.14e',1e-7*$temperature**1.75/101325*1e5/(42.88**(1/3)+20.1**(1/3))**2);
					# $str_temp =~ s/e/d/;
					# $cs_coef_hydr[0][0] .= "\t\t\tD = $str_temp*sqrt((m+28.9d0)/(m*28.9d0))\n";
					# $cs_coef_hydr[0][0] .= "\t\t\tKn = $string1/rbg\n";
					# if($molecule_name[$mol_types_used[1]] eq 'A'){
						# # the so-called accommodation coefficient is 0.65 for acid
						# $cs_coef_hydr[0][0] .= "\t\t\tcs(i) = 4.d0*$string4*D*rbg*(1.d0+Kn)/(1.d0+2.d0*Kn*(1.d0+Kn)/0.65)*cbg\n";
					# }else{
						# die "You have a one-component system, but the component is not acid (A)??\n";
					# }
					# $cs_coef_hydr[0][0] .= "\t\telse\n";
				# }
				# $str_temp = "\t";
				# $str_temp2 = "\t\tend if\n";
			# }else{
				# $str_temp = "";
				# $str_temp2 = "";
			# }
			$str_temp = "";
			$str_temp2 = "";
				
			$cs_coef_hydr[0][0] .= "$str_temp\t\tD = $string2/(2.d0*r)*((5.d0+4.d0*($string1/r)+&\n\t\t\t\t& 6.d0*($string1/r)**2.d0+18.d0*($string1/r)**3)/&\n\t\t\t\t& (5.d0-($string1/r)+(8.d0+$string4)*($string1/r)**2.d0))\n";
			$cs_coef_hydr[0][0] .= "$str_temp\t\tvth = sqrt($string3/m)\n";
			$cs_coef_hydr[0][0] .= "$str_temp\t\tKn = 2.d0*(D+Dbg)/(sqrt(vth**2.d0+vthbg**2.d0)*(r+rbg))\n";
            $cs_coef_hydr[0][0] .= "$str_temp\t\tcs(i) = 4.d0*$string4*(r+rbg)*(D+Dbg)*(1.d0+Kn)/(1.d0+2.d0*Kn*(1.d0+Kn))";
			if(!$variable_cs){
				$cs_coef_hydr[0][0] .= "*cbg";
			}
			$cs_coef_hydr[0][0] .= "\n";
				
			$cs_coef_hydr[0][0] .= $str_temp2;
		}

################################################################################
################################################################################
##         9.12 Coagulation sink from an external user-provided subroutine    ##
################################################################################
################################################################################

    }elsif($coag_terms =~ m/^external$/i){
        # Print out the call to the external routine
        # Possible special coagulation losses for specific clusters are taken into account below
        print OUT "\t! cs obtained from an external routine\n";
        print OUT "\tcall get_scav_parameters$append_to_ext_names(temperature=temperature,cs_per_clust=cs)\n\n";
        
################################################################################
################################################################################
##         9.13 Coagulation sink given by one number                          ##
################################################################################
################################################################################

	}elsif(&is_pos_number($coag_terms)){
		# Same coagulation frequency for all
		$coag_terms =~ s/E/e/;
		if($#cs_only>=0){
			if($lfortran){
				$cs_term_temp = sprintf('%.14e',$coag_terms);
			}else{
				$cs_term_temp = $coag_terms;
			}
		}else{
			if($lfortran && !$variable_cs){
				$str_temp=sprintf('%.14e',$coag_terms);
				$str_temp =~ s/e/d/;
				print OUT "\tcs = $str_temp\n";
			}elsif(!$lfortran){
				print CS "CS = $coag_terms;\n";
			}
		}
	}else{
		die "\nCan't understand coagulation sink definition $coag_terms.\n\n";
	}
	
############################################################################################
############################################################################################
##         9.14 Coagulation sink for specific clusters from the command line              ##
############################################################################################
############################################################################################

# If we have special losses for some clusters, get them here
	if($#cs_only>=0){
		if(!$lloop){
			# go through the input and separate the cluster and the rate
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				$cs_only_hydr[$iclus] = ();
			}
			for($icol=0;$icol<=$#cs_only;$icol++){
				@columns=split(',',$cs_only[$icol]);
				if ($#columns!=1){
					die "Can't understand the special coagulation loss $cs_only[$icol] - the format should be 'clust,number'.\n";
				}
				($iclus,$nwaters)=&get_corresponding_dry($columns[0]);
				if($iclus eq ''){
					die "Cluster $columns[0] from the special coagulation loss $cs_only[$icol] does not exist.\n";
				}
				$cs_only_hydr[$iclus][$nwaters] = sprintf('%.14e',$columns[1]);
			}
			
			# Then calculate the hydrate averages if needed or just put the values back in the same array
			@cs_only = ();
			$icol = -1;
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				next if ($#{ $cs_only_hydr[$iclus] }==-1);
				$icol += 1;
				$cs_only[$icol][0] = $iclus;
				$cs_only[$icol][1] = 0;
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						if(defined $cs_only_hydr[$iclus][$ihydr]){
							$cs_only[$icol][1] += $distr[$iclus][$ihydr]*$cs_only_hydr[$iclus][$ihydr];
						}else{
							if($#{ $cs_only_hydr[$iclus] }==0){
								print "You have defined special coagulation losses for $label[$iclus] but not its hydrates -> using the given value for the hydrate average.\n";
								$cs_only[$icol][1] = $cs_only_hydr[$iclus][0];
								last;
							}else{
								print "You have defined special coagulation losses for some but not all hydrates of $label[$iclus] -> using the standard coagulation losses for the others.\n";
								if($one_cs_for_almost_all){
									$cs_only[$icol][1] += $distr[$iclus][$ihydr]*$cs_term_temp;
								}else{
									$cs_only[$icol][1] += $distr[$iclus][$ihydr]*$cs_coef_hydr[$iclus][$ihydr];
								}
							}
						}
					}
				}
			}
		}else{
			$lines{'loss_only'} = '';
			for($icol=0;$icol<=$#cs_only;$icol++){
				@columns=split(',',$cs_only[$icol]);
				if ($#columns!=1){
					die "Can't understand the special coagulation loss $cs_only[$icol] - the format should be 'clust,number'.\n";
				}
				$valid = 1;
				($string1,$string2) = &determine_cluster_composition($columns[0]);
				@temp_array=@$string1;
				if($string2 ne '' || sum(@temp_array)>sum(@temp_array[@mol_types_used[1..$nmol_types_used]])){
					# cluster contains molecule types not included in the system
					$valid = 0;
				}
				if(!$valid){
					die "Special coagulation loss cluster $columns[0] is not a valid cluster\n";
				}
				if($nmol_types_used>1){
					$iclus = "clust_from_indices(".join(',',@temp_array[@mol_types_used[1..$nmol_types_used]]).")";
				}else{
					$imol=1;
					$iclus = $temp_array[$mol_types_used[$imol]];
				}
				$string1 = sprintf('%.14e',$columns[1]);
				$string1 =~ s/e/d/;
				$lines{'loss_only'} .= "\tcs($iclus) = $string1\n";
			}
		}
	}
	if(!$lloop && $one_cs_for_almost_all){
		# If we have a constant coagulation loss for most clusters and a special value for others,
		# print the coefficients here.
		for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
			$str_temp = $cs_term_temp;
			for($icol=0;$icol<=$#cs_only;$icol++){
				if($cs_only[$icol][0]==$iclus){
					$str_temp = sprintf('%.14e',$cs_only[$icol][1]);
					if(!&is_pos_number($str_temp)){
						die "\nCan't understand coagulation loss definition $str_temp for cluster $label[$iclus]\n";
					}elsif(!$lsilent){
						print "Using special coagulation loss $str_temp for cluster $label[$iclus].\n";
					}
					last;
				}
			}
			if($lfortran){
				$str_temp =~ s/e/d/;
				print OUT "\tcs($iclus) = $str_temp\t! coagulation loss of $label[$iclus]\n";
			}else{
				print CS "CS($iclus) = $str_temp;\t% coagulation loss of $label[$iclus]\n";
			}
		}

################################################################################
################################################################################
##         9.15 Printing out size-dependent sink in dry case                  ##
################################################################################
################################################################################
	
	}elsif(!$lhydrate_average && !$one_cs_for_all){
		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
                $cs_term_temp="";
                if($coag_terms !~ m/^external$/i){
                    $cs_term_temp=sprintf('%.14e',$cs_coef_hydr[$iclus][0]);
                }
				# If there are some special cases, going through those now
				if($#cs_only>=0){
					for($icol=0;$icol<=$#cs_only;$icol++){
						if($cs_only[$icol][0]==$iclus){
							$cs_term_temp = sprintf('%.14e',$cs_only[$icol][1]);
							if(!&is_pos_number($cs_term_temp)){
								die "\nCan't understand coagulation loss definition $cs_term_temp for cluster $label[$iclus]\n";
							}elsif(!$lsilent){
								print "Using special coagulation loss $cs_term_temp for cluster $label[$iclus].\n";
							}
							last;
						}
					}
				}

				if($cs_term_temp ne ''){
                    if($lfortran){
                        $cs_term_temp =~ s/e/d/;
                        print OUT "\tcs($iclus) = $cs_term_temp\t! coagulation loss of $label[$iclus]\n";
                    }else{
                        print CS "CS($iclus) = $cs_term_temp;\t% coagulation loss of $label[$iclus]\n";
                    }
                }
			}
		}else{
			print OUT "\tdo i = 1,$nclust_included\n";
			if($nmol_types_used>1){
				print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,indices(i,:))\n";
			}else{
				print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,i)\n";
			}
			print OUT $cs_coef_hydr[0][0];
			print OUT "\tend do\n\n";
		}
	
################################################################################
################################################################################
##         9.16 Hydrate average for size-dependent sink                       ##
################################################################################
################################################################################	
	
	}elsif(!$one_cs_for_all){
		
		if($lfortran){
			print OUT "\t! The coagulation loss coefficients are averaged over all the available hydrates\n\t! Dry values are printed as comments for reference\n\n";
		}else{
			print CS "% The coagulation loss coefficients are averaged over all the available hydrates\n% Dry values are printed as comments for reference\n\n";
		}
		
		for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
			$cs_term_temp="";
            if($coag_terms !~ m/^external$/i){
                $cs_term_temp=0.0;
                for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
                    if(defined $distr[$iclus][$ihydr]){
                        $cs_term_temp += $distr[$iclus][$ihydr]*$cs_coef_hydr[$iclus][$ihydr];
                    }
                }
                $cs_term_temp=sprintf('%.14e',$cs_term_temp);
            
                # dry value
                if(defined $distr[$iclus][0]){
                    $str_temp=sprintf('%.14e',$cs_coef_hydr[$iclus][0]);
                }else{
                    $str_temp="undefined";
                }
                $str_temp2="";
			}
            
			# If there are some special cases, going through those now
			if($#cs_only>=0){
				for($icol=0;$icol<=$#cs_only;$icol++){
					if($cs_only[$icol][0]==$iclus){
						$cs_term_temp = sprintf('%.14e',$cs_only[$icol][1]);
						$str_temp=sprintf('%.14e',$cs_only_hydr[$iclus][0]);
						$str_temp2=" (using a special coagulation loss)";
						if(!&is_pos_number($cs_term_temp)){
							die "\nCan't understand coagulation loss definition $cs_term_temp for cluster $label[$iclus]\n";
						}elsif(!$lsilent){
							print "Using special coagulation loss $cs_term_temp for cluster $label[$iclus].\n";
						}
						last;
					}
				}
			}
            if($cs_term_temp ne ''){
                if($lfortran){
                    $cs_term_temp =~ s/e/d/;
                    $str_temp =~ s/e/d/;
                    if($lhas_hydr[$iclus]){
                        $string="$cs_term_temp\t! coagulation loss of $label[$iclus], dry value $str_temp$str_temp2";
                    }else{
                        $string="$cs_term_temp\t! coagulation loss of $label[$iclus], no hydrates$str_temp2";
                    }
                    print OUT "\tcs($iclus) = $string\n";
                }else{
                    if($lhas_hydr[$iclus]){
                        $string="CS($iclus) = $cs_term_temp;\t% coagulation loss of $label[$iclus], dry value $str_temp$str_temp2";
                    }else{
                        $string="CS($iclus) = $cs_term_temp;\t% coagulation loss of $label[$iclus], no hydrates$str_temp2";
                    }
                    print CS "$string\n";
                }
            }
		}
	}
	
	# Adding to the loop mode the values that are not included in the do-loops
	if($lloop){
		if($#cs_only>=0){
			print OUT $lines{'loss_only'}."\n";
		}
		if($variable_cs){
			if($one_cs_for_all){
				print OUT "\tcs = coef(" . ($variable_temp+1) . ")\n\n";
			}else{
				print OUT "\tcs = coef(" . ($variable_temp+1) . ")*cs\n\n";
			}
		}
	}

	if(! $lfortran){
		print CS "\n";
		close(CS);
	}

}elsif(! $lfortran){
	print CS "% CS terms disabled\n\n";
	if($include_ion_terms){
			print CS "% enhancement factor for ions\nfcs = nan;\n\n";
	}
	print CS "CS = [];\n";
	close(CS);
}


################################################################################
################################################################################
##      9.2 Wall losses                                                       ##
################################################################################
################################################################################

if(! $lfortran){
	print WL "% Wall losses\n\n";
	if($include_ion_terms){
		print WL "% enhancement factor for ions\nfwl = $fwl;\n\n";
	}
}
if(!$disable_wall_terms || ($l_mcmc_any && $ncoef_wl>0)){
	if($lfortran){
		print OUT "\n\t! wall losses\n\n";
	}
	# array for the wall loss coefficients of the hydrates
	@wl_coef_hydr=();
	
################################################################################
################################################################################	
##         9.21 Reading in wall losses for all the clusters from a given file ##
################################################################################
################################################################################

	if($wall_terms eq 'wlfile'){
        if(!$lsilent){
            print "\nWall loss rate file: $wl_coef_file_name\n";
        }
		open(WL_IN, "<$wl_coef_file_name") || die "\nCould not open wall loss rate file $wl_coef_file_name\n\n";
		chomp(@temp_array=<WL_IN>);
		close(WL_IN);
		$number_of_lines=$#temp_array;
		for($iline=0;$iline<=$number_of_lines;$iline++){
			next if ($temp_array[$iline] =~ /^\#/);
			if($temp_array[$iline] =~ /(\d+$name_water-?\d+)|(\d+$name_water\s*$)/){
				die "$wl_coef_file_name: Wall loss rate cannot be given for hydrates for now (if hydrate averaging is used, the given rate for dry clusters is taken to be the effective rate)";
			}
			@columns=split(' ',$temp_array[$iline]);			
			die "\n$columns[0] on line $iline in file $wl_coef_file_name should be a number\n\n" if (!&is_pos_number($columns[0]));
			die "\nThere should be two columns on line $iline in file $wl_coef_file_name: the rate and the cluster\n\n" if ($#columns != 1);
		
			$iclus=&get_cluster_number($columns[1]);
			if($iclus ne ''){
				$wl_coef_hydr[$iclus][0]=$columns[0];
			}
		}
		for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
			if(!defined $wl_coef_hydr[$iclus][0]){
				die "\nCould not find loss rate for $label[$iclus] from $wl_coef_file_name!\n\n";
			}
		}

		
################################################################################
################################################################################
##         9.22 Wall loss parameterizations                                   ##
################################################################################
################################################################################

	
##############################################################################################
##############################################################################################
##            9.221 Cloud 4 wall loss parameterization from the Excel file by Jasper Kirkby ##
##############################################################################################
##############################################################################################

	}elsif($wall_terms =~ m/^cloud4_JK$/i){
	# CLOUD wall losses (parameterization from experiments)
		
		if($variable_temp){
			die "\nVariable temperature not implemented for the cloud4_JK option.\n\n";
		}
		
		$air_viscosity = 1.708e-5*($temperature/273.15)**1.5*393.396/($temperature+120.246);
		
		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				# loss coefficients for the dry cluster and possible hydrates
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						$mass1=$clust_mass[$iclus][$ihydr];
						$radius=$clust_radius[$iclus][$ihydr];
						# mobility diameter:
						$diameter = (2.0*$radius+0.3e-9)*sqrt(1+28.8*$mass_conv/$mass1);
						# slip correction factor:
						$wl_term_temp = 1+2.e-9/(101300*$diameter*.752e-6)*(6.32+2.01*exp(-0.1095e9*101300*$diameter*.752e-6));
						# diffusion coefficient (m^2/s):
						$wl_term_temp *= $boltz*$temperature/(3.*$pi*$air_viscosity*$diameter);
						# CLOUD4 wall loss (1/s):
						$wl_coef_hydr[$iclus][$ihydr] = .774*sqrt($wl_term_temp);	
					}
				}
			}
		}else{
			$wl_coef_hydr[0][0] = "\t\td = (2.d0*r+0.3d-9)*sqrt(1.d0+28.8d0/m)\n";
			$str_temp = sprintf('%.14e',2.e-9/(101300*.752e-6));
			$str_temp =~ s/e/d/;
			$str_temp2 = sprintf('%.14e',-0.1095e9*101300*.752e-6);
			$str_temp2 =~ s/e/d/;
			$wl_coef_hydr[0][0] .= "\t\tsc = 1.d0+$str_temp*(6.32d0+2.01d0*exp($str_temp2*d))/d\n";
			$str_temp = sprintf('%.14e',$boltz*$temperature/(3.*$pi*$air_viscosity));
			$str_temp =~ s/e/d/;
			$wl_coef_hydr[0][0] .= "\t\twl(i) = .774d0*sqrt(sc*$str_temp/d)\n";
		}

#################################################################################
#################################################################################
##            9.222 Cloud 4 wall loss parameterization from Andreas Kürten     ##
#################################################################################
#################################################################################

	}elsif($wall_terms =~ m/^cloud4_AK$/i){
	# CLOUD wall losses (parameterization from experiments)
		
		if($variable_temp){
			die "\nVariable temperature not implemented for the cloud4_AK option.\n\n";
		}
		
		$air_viscosity = (11.798+0.629976*$temperature-1.81158e-04*$temperature**2)*1e-07;
		
		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
			
				# loss coefficients for the dry cluster and possible hydrates
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						$mass1=$clust_mass[$iclus][$ihydr];
						$radius=$clust_radius[$iclus][$ihydr];
						# mobility diameter:
						$diameter = 2.0*$radius;   				##### Note: this is for some reason the geometric diameter.
						# lambda (at pressure 100000 Pa)
						$wl_term_temp = $boltz*$temperature/(sqrt(2)*100000*$pi*(0.37e-09)**2);
						# Knudsen number
						$wl_term_temp /= $diameter;
						# slip correction factor:
						$wl_term_temp = 1+$wl_term_temp*(1.142+0.558*exp(-0.999/$wl_term_temp));
						# diffusion coefficient (m^2/s):
						$wl_term_temp *= $boltz*$temperature/(3.*$pi*$air_viscosity*$diameter);
						# CLOUD4 wall loss (1/s):
						$wl_coef_hydr[$iclus][$ihydr] = .77*sqrt($wl_term_temp);	
					}
				}
			}
		}else{
			$wl_coef_hydr[0][0] = "\t\td = 2.d0*r\n";
			$str_temp = sprintf('%.14e',$boltz*$temperature/(sqrt(2)*100000*$pi*(0.37e-09)**2));
			$str_temp =~ s/e/d/;
			$wl_coef_hydr[0][0] .= "\t\tsc = 1.d0+$str_temp*(1.142d0+0.558d0*exp(-0.999d0/$str_temp*d))/d\n";
			$str_temp = sprintf('%.14e',$boltz*$temperature/(3.*$pi*$air_viscosity));
			$str_temp =~ s/e/d/;
			$wl_coef_hydr[0][0] .= "\t\twl(i) = .77d0*sqrt(sc*$str_temp/d)\n";
		}

###################################################################################################################
###################################################################################################################
##            9.223 Cloud 4 wall loss parameterization used in the paper by Joao Almeida et al., 2013            ##
###################################################################################################################
###################################################################################################################
	
	}elsif($wall_terms =~ m/^cloud4_JA$/i){
	# CLOUD wall losses (parameterization from experiments)
		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				# loss coefficients for the dry cluster and possible hydrates
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						$mass1=$clust_mass[$iclus][$ihydr];
						$radius=$clust_radius[$iclus][$ihydr];
					
						# WL factor proportional to 1/mobility diameter
						$wl_term_temp = 1.0/((2.0*$radius+0.3e-9)*sqrt(1+28.8*$mass_conv/$mass1));
						$wl_term_temp *= 1.66e-12;
						$wl_coef_hydr[$iclus][$ihydr] = $wl_term_temp;
					}
				}
			}
		}else{
			$wl_coef_hydr[0][0] = "\t\twl(i) = 1.66d-12/((2.d0*r+0.3d-9)*sqrt(1.d0+28.8d0/m))\n";
		}

##########################################################################################################################
##########################################################################################################################
##            9.224 Simplified Cloud 4 wall loss parameterization based on the paper by Andreas Kürten et al., 2015     ##
##########################################################################################################################
##########################################################################################################################

	}elsif($wall_terms =~ m/^cloud4_simple$/i){
	# CLOUD wall losses (parameterization from experiments, very simple)
		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				# loss coefficients for the dry cluster and possible hydrates
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						$mass1=$clust_mass[$iclus][$ihydr];
						$radius=$clust_radius[$iclus][$ihydr];
					
						# WL factor proportional to 1/mobility diameter; mobility diameter = mass diameter + 0.3 nm (no mass dependence)
						$wl_term_temp = 1.0/(2.0*$radius+0.3e-9);
						$wl_term_temp *= 1.0e-12;
						$wl_coef_hydr[$iclus][$ihydr] = $wl_term_temp;
					}
				}
			}
		}else{
			$wl_coef_hydr[0][0] = "\t\twl(i) = 1.d-12/(2.d0*r+0.3d-9)\n";
		}

#################################################################################
#################################################################################
##            9.225 Cloud 3 wall loss parameterization                         ##
#################################################################################
#################################################################################
	
	}elsif($wall_terms =~ m/^cloud3$/i){
	# CLOUD wall losses (parameterization from experiments)
		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				# loss coefficients for the dry cluster and possible hydrates
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						$mass1=$clust_mass[$iclus][$ihydr];
						$radius=$clust_radius[$iclus][$ihydr];

						# WL factor proportional to 1/mobility diameter
						$wl_term_temp = 1.0/((2.0*$radius+0.3e-9)*sqrt(1+28.8*$mass_conv/$mass1));
						$wl_term_temp *= 1.310e-12;
						$wl_coef_hydr[$iclus][$ihydr] = $wl_term_temp;
					}
				}
			}
		}else{
			$wl_coef_hydr[0][0] = "\t\twl(i) = 1.31d-12/((2.d0*r+0.3d-9)*sqrt(1.d0+28.8d0/m))\n";
		}
		
###############################################################################################################
###############################################################################################################
##            9.226 Diffusion wall loss for a flow tube (originally for the tube of Hanson and Eisele, 2000) ##
###############################################################################################################
###############################################################################################################
	
	}elsif($wall_terms =~ m/^diffusion$/i){
		# Loss terms based on diffusion in a flow tube (originally for modeling the setup of Hanson and Eisele, 2000)
		# Diffusion coefficients are calculated as in the kinetic gas theory, and relative to the coefficient of sulfuric acid
		
		if($variable_temp){
			die "\nVariable temperature not implemented for the diffusion loss option.\n\n";
		}
	
		# Conversion from diffusion coefficient to wall loss factor
		if($tube_radius_in ne ''){
			$tube_radius=$tube_radius_in/100;
		}else{
			$tube_radius=0.049/2; # m (Hanson and Eisele, 2000)
		}		
		$D_to_wl=3.65/$tube_radius**2; # for laminar diffusion-limited flow (Brown, R.L.: Tubular flow reactor with first-order kinetics, J. Res. Natl. Bur. Stand. (U.S.), 83, 1, 1-6, 1978)
		
		# Properties of N2, the radius is calculated from viscosity (e.g. eq. 11-67 in Present: Kinetic theory of gases, 1958)
		$mass_N2=28.01*$mass_conv;
		
		
		# Sutherland formula, coefficients for N2:
		# C=111 from Crane (1988) (haven't seen the original paper, but lots of references citing the number)
		# mu0=17.9 at T0=300 from CRC
		
		$viscosity_N2=17.9*1e-6*(300+111)/($temperature+111)*($temperature/300)**1.5;
		$radius_N2=0.5*(5/16/$viscosity_N2)**0.5*($mass_N2*$boltz*$temperature/$pi)**0.25;
	
		# find the acid monomer
		$iclus=&get_cluster_number('1A');
		if($iclus eq ''){
			die "\nCan't calculate diffusion coefficients relative to that of sulfuric acid, if you don't have acid in the system\n\n";
		}else{
			$mass1=$clust_mass[$iclus][0];
			$radius=$clust_radius[$iclus][0];
		}

		# Loss coefficient of the acid monomer
		# Diffusion coefficient of acid in N2 (e.g. eq. 8-87 in Present: Kinetic theory of gases, 1958)
		# (experimental coefficient from Hanson and Eisele is 0.094 +- 0.0012 atm cm^2 s^-1)
		$D_acid_N2=3/8/101325*$boltz*$temperature/($radius+$radius_N2)**2*sqrt($boltz*$temperature/2/$pi*(1/$mass1+1/$mass_N2)); # at 1 atm
		if($tube_pressure_in ne ''){
			$wl_term_0=$D_acid_N2/($tube_pressure_in/101325)*$D_to_wl; # s^-1, converted to the given pressure
		}else{
			$wl_term_0=$D_acid_N2/(133.322/101325*620)*$D_to_wl; # s^-1, converted to 620 Torr (Hanson and Eisele, 2000)
		}

		$D0_factor=1/($radius+$radius_N2)**2*sqrt(1/$mass1+1/$mass_N2);
	
		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				# loss coefficients for the dry cluster and possible hydrates
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(defined $distr[$iclus][$ihydr]){
						$mass1=$clust_mass[$iclus][$ihydr];
						$radius=$clust_radius[$iclus][$ihydr];
					
						$D_factor=1/($radius+$radius_N2)**2*sqrt(1/$mass1+1/$mass_N2);
						$wl_coef_hydr[$iclus][$ihydr]=$D_factor/$D0_factor*$wl_term_0;
					}
				}
			}
		}else{
			$radius_N2 = sprintf('%.14e',$radius_N2);
			$radius_N2 =~ s/e/d/;
			$mass_N2 = sprintf('%.14e',$mass_N2);
			$mass_N2 =~ s/e/d/;
			$D0_factor = sprintf('%.14e',$D0_factor);
			$D0_factor =~ s/e/d/;
			$wl_term_0 = sprintf('%.14e',$wl_term_0);
			$wl_term_0 =~ s/e/d/;
			$wl_coef_hydr[0][0] = "\t\twl(i) = 1.d0/(r+$radius_N2)**2.d0*sqrt(1.d0/m+1.d0/$mass_N2)/$D0_factor*$wl_term_0\n";
		}
		
		
################################################################################
################################################################################
##         9.23 Wall losses given by one number                               ##
################################################################################
################################################################################


################################################################################
################################################################################
##            9.231 Ift flow tube wall loss                                   ##
################################################################################
################################################################################
	
	}elsif($wall_terms =~ m/ift/i){
	# Ift-lft wall losses (estimated, Berndt & Richters, 2011, http://dx.doi.org/10.1016/j.atmosenv.2011.10.060)
		
		$wl_term_temp = 2.3e-2;
		
		if($#wl_only>=0){
			if($lfortran){
				$wl_term_temp = sprintf('%.14e',$wl_term_temp);
			}
		}else{
			if($lfortran){
				$str_temp=sprintf('%.14e',$wl_term_temp);
				$str_temp =~ s/e/d/;
				print OUT "\twl = $str_temp\n";
			}else{
				print WL "WL = $wl_term_temp;\n";
			}
		}
	
################################################################################
################################################################################
##            9.232 Other size-independent wall loss                          ##
################################################################################
################################################################################
	
	}elsif(&is_pos_number($wall_terms)){
	# Other wall losses (same number for all)
		$wall_terms =~ s/E/e/;
		if($#wl_only>=0){
			if($lfortran){
				$wl_term_temp = sprintf('%.14e',$wall_terms);
			}else{
				$wl_term_temp = $wall_terms;
			}
		}else{
			if($lfortran){
				$str_temp=sprintf('%.14e',$wall_terms);
				$str_temp =~ s/e/d/;
				print OUT "\twl = $str_temp\n";
			}else{
				print WL "WL = $wall_terms;\n";
			}
		}

	}else{	
		die "\nCan't understand wall loss definition $wall_terms.\n\n";
	}
	
	
############################################################################################
############################################################################################
##         9.24 Wall losses for specific clusters from the command line                   ##
############################################################################################
############################################################################################
	
	# If we have special wall losses for some clusters,
	if($#wl_only>=0){
		# go through the input and separate the cluster and the rate
		for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
			$wl_only_hydr[$iclus] = ();
		}
		for($icol=0;$icol<=$#wl_only;$icol++){
			@columns=split(',',$wl_only[$icol]);
			if ($#columns!=1){
				die "Can't understand the special wall loss $wl_only[$icol] - the format should be 'clust,number'.\n";
			}
			($iclus,$nwaters)=&get_corresponding_dry($columns[0]);
			if($iclus eq ''){
				die "Cluster $columns[0] from the special wall loss $wl_only[$icol] does not exist.\n";
			}
			$wl_only_hydr[$iclus][$nwaters] = sprintf('%.14e',$columns[1]);
		}
		
		# Then calculate the hydrate averages if needed or just put the values back in the same array
		@wl_only = ();
		$icol = -1;
		for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
			next if ($#{ $wl_only_hydr[$iclus] }==-1);
			$icol += 1;
			$wl_only[$icol][0] = $iclus;
			$wl_only[$icol][1] = 0;
			for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
				if(defined $distr[$iclus][$ihydr]){
					if(defined $wl_only_hydr[$iclus][$ihydr]){
						$wl_only[$icol][1] += $distr[$iclus][$ihydr]*$wl_only_hydr[$iclus][$ihydr];
					}else{
						if($#{ $wl_only_hydr[$iclus] }==0){
							print "You have defined special wall losses for $label[$iclus] but not its hydrates -> using the given value for the hydrate average.\n";
							$wl_only[$icol][1] = $wl_only_hydr[$iclus][0];
							last;
						}else{
							print "You have defined special wall losses for some but not all hydrates of $label[$iclus] -> using the standard wall losses for the others.\n";
							if($one_wl_for_almost_all){
								$wl_only[$icol][1] += $distr[$iclus][$ihydr]*$wl_term_temp;
							}else{
								$wl_only[$icol][1] += $distr[$iclus][$ihydr]*$wl_coef_hydr[$iclus][$ihydr];
							}
						}
					}
				}
			}
		}
	}
	if($one_wl_for_almost_all){
		# If we have a constant wall loss for most clusters and a special value for others,
		# print the coefficients here.
		if($#wl_only>=0){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				$str_temp = $wl_term_temp;
				for($icol=0;$icol<=$#wl_only;$icol++){
					if($wl_only[$icol][0]==$iclus){
						$str_temp = sprintf('%.14e',$wl_only[$icol][1]);
						if(!&is_pos_number($str_temp)){
							die "\nCan't understand wall loss definition $str_temp for cluster $label[$iclus]\n";
						}elsif(!$lsilent){
							print "Using special wall loss $str_temp for cluster $label[$iclus].\n";
						}
						last;
					}
				}
				if($lfortran){
					$str_temp =~ s/e/d/;
					print OUT "\twl($iclus) = $str_temp\t! wall loss of $label[$iclus]\n";
				}else{
					print WL "WL($iclus) = $str_temp;\t% wall loss of $label[$iclus]\n";
				}
			}
		}
		
		
		# If we have MCMC wall losses for some clusters and a size-independent value for others,
		# print the MCMC coefficients here.
		if($l_mcmc_any){
			if($l_wl_mcmc){
				print OUT "\twl = coef($n_mcmc_coefs)\t\t\t\t! wall loss\n";
				$coef_true[$n_mcmc_coefs] = '';
			}
			$icoef_wl = $n_mcmc_coefs-$ncoef_wl;
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				if($l_special_mcmc_wl[$iclus]){
					$icoef_wl++;
					print OUT "\twl($iclus) = coef($icoef_wl)\t\t\t! wall loss of $label[$iclus]\n";
					$coef_true[$icoef_wl] = '';
				}
			}
		}
	
################################################################################
################################################################################
##         9.25 Printing out size-dependent wall losses in dry case           ##
################################################################################
################################################################################
	
	}elsif((!$lhydrate_average || $wall_terms eq 'wlfile') && !$one_wl_for_all){
		if($wall_terms eq 'wlfile'){
			$string=", given as input";
		}else{
			$string="";
		}
		if($l_mcmc_any){
			$icoef_wl = $n_mcmc_coefs-$ncoef_wl;
		}
		if(!$lloop){
			for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
				$wl_term_temp=sprintf('%.14e',$wl_coef_hydr[$iclus][0]);
				# If there are some special cases, going through those now
				if($#wl_only>=0){
					for($icol=0;$icol<=$#wl_only;$icol++){
						if($wl_only[$icol][0]==$iclus){
							$wl_term_temp = sprintf('%.14e',$wl_only[$icol][1]);
							if(!&is_pos_number($wl_term_temp)){
								die "\nCan't understand wall loss definition $wl_term_temp for cluster $label[$iclus]\n";
							}elsif(!$lsilent){
								print "Using special wall loss $wl_term_temp for cluster $label[$iclus].\n";
							}
							last;
						}
					}
				}

				if($lfortran){
					$wl_term_temp =~ s/e/d/;
					if($l_special_mcmc_wl[$iclus]){
						# If this is an MCMC coefficient, save the true value to be printed later ...
						$icoef_wl++;
						$coef_true[$icoef_wl] = "$wl_term_temp\t! wall loss of $label[$iclus]$string";
						# ... and print here just the MCMC coefficient
						print OUT "\twl($iclus) = coef($icoef_wl)\t\t\t\t! wall loss of $label[$iclus]\n";
					}else{
						print OUT "\twl($iclus) = $wl_term_temp\t! wall loss of $label[$iclus]$string\n";
					}
				}else{
					print WL "WL($iclus) = $wl_term_temp;\t% wall loss of $label[$iclus]$string\n";
				}
			}
		}else{
			print OUT "\tdo i = 1,$nclust_included\n";
			if($nmol_types_used>1){
				print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,indices(i,:))\n";
			}else{
				print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,i)\n";
			}
			print OUT $wl_coef_hydr[0][0];
			print OUT "\tend do\n\n";
		}
	
################################################################################
################################################################################
##         9.26 Hydrate average for size-dependent wall losses                ##
################################################################################
################################################################################	
	
	}elsif(!$one_wl_for_all){
	
		if($l_mcmc_any){
			$icoef_wl = $n_mcmc_coefs-$ncoef_wl;
		}
		
		if($lfortran){
			print OUT "\t! The wall loss coefficients are averaged over all the available hydrates\n\t! Dry values are printed as comments for reference\n\n";
		}else{
			print WL "% The wall loss coefficients are averaged over all the available hydrates\n% Dry values are printed as comments for reference\n\n";
		}
		
		for($iclus=1;$iclus<=$max_cluster_number;$iclus++){
			$wl_term_temp=0.0;
			for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
				if(defined $distr[$iclus][$ihydr]){
					$wl_term_temp += $distr[$iclus][$ihydr]*$wl_coef_hydr[$iclus][$ihydr];
				}
			}

			$wl_term_temp=sprintf('%.14e',$wl_term_temp);
			# dry value
			$str_temp=sprintf('%.14e',$wl_coef_hydr[$iclus][0]);
			$str_temp2="";
			
			# If there are some special cases, going through those now
			if($#wl_only>=0){
				for($icol=0;$icol<=$#wl_only;$icol++){
					if($wl_only[$icol][0]==$iclus){
						$wl_term_temp = sprintf('%.14e',$wl_only[$icol][1]);
						$str_temp=sprintf('%.14e',$wl_only_hydr[$iclus][0]);
						$str_temp2=" (using a special wall loss)";
						if(!&is_pos_number($wl_term_temp)){
							die "\nCan't understand wall loss definition $wl_term_temp for cluster $label[$iclus]\n";
						}elsif(!$lsilent){
							print "Using special wall loss $wl_term_temp for cluster $label[$iclus].\n";
						}
						last;
					}
				}
			}

			if($lfortran){
				$wl_term_temp =~ s/e/d/;
				$str_temp =~ s/e/d/;
				if($lhas_hydr[$iclus]){
					$string="$wl_term_temp\t! wall loss of $label[$iclus], dry value $str_temp$str_temp2";
				}else{
					$string="$wl_term_temp\t! wall loss of $label[$iclus], no hydrates$str_temp2";
				}
				if($l_special_mcmc_wl[$iclus]){
					# If this is an MCMC coefficient, save the true value to be printed later ...
					$icoef_wl++;
					$coef_true[$icoef_wl] = "$string";
					# ... and print here just the MCMC coefficient
					print OUT "\twl($iclus) = coef($icoef_wl)\t\t\t\t! wall loss of $label[$iclus]\n";
				}else{
					print OUT "\twl($iclus) = $string\n";
				}
			}else{
				if($lhas_hydr[$iclus]){
					$string="WL($iclus) = $wl_term_temp;\t% wall loss of $label[$iclus], dry value $str_temp$str_temp2";
				}else{
					$string="WL($iclus) = $wl_term_temp;\t% wall loss of $label[$iclus], no hydrates$str_temp2";
				}
				print WL "$string\n";
			}
		}
	}
		
	if(! $lfortran){
		print WL "\n";
		close(WL);
	}
}elsif(! $lfortran){
	print WL "% WL terms disabled\n\n";
	if($include_ion_terms){
		print WL "% enhancement factor for ions\nfwl = nan;\n\n";
	}
	print WL "WL = [];\n";
	close(WL);
}

################################################################################
################################################################################
##         9.3 Input sink from an external user-provided subroutine           ##
################################################################################
################################################################################

if(!$disable_input_sink){
    
    # Print out the call to the external routine
    # Possible special losses for specific clusters are taken into account below
    print OUT "\n\t! Input sink obtained from an external routine\n";
    print OUT "\tcall $routine_insink(insink=insink)\n\n";
    
################################################################################
################################################################################
##         9.31 Input sink for specific clusters from the command line        ##
################################################################################
################################################################################

# If we have special losses for some clusters, get them here
	if($#insink_only>=0){
		if(!$lloop){
            @temp_array = @insink_only;
            @insink_only = ();
            for($icol=0;$icol<=$#temp_array;$icol++){
				@columns=split(',',$temp_array[$icol]);
				if ($#columns!=1){
					die "Can't understand the special input sink $temp_array[$icol] - the format should be 'clust,number'.\n";
				}
				($iclus,$nwaters)=&get_corresponding_dry($columns[0]);
				if($iclus eq ''){
					die "Cluster $columns[0] from the special input sink $temp_array[$icol] does not exist.\n";
				}elsif($nwaters > 0){
                    die "Cluster $columns[0] from the special input sink $temp_array[$icol]: not possible to include hydrates for the input sink.\n";
                }
                $str_temp = sprintf('%.14e',$columns[1]);
                if(!&is_pos_number($str_temp)){
                    die "\nCan't understand input sink definition $str_temp for cluster $label[$iclus]\n";
                }elsif(!$lsilent){
                    print "Using special input sink $str_temp for cluster $label[$iclus].\n";
                }
                $insink_only[$icol][0] = $iclus;
                $insink_only[$icol][1] = $str_temp;
                if($lfortran){
                    $str_temp =~ s/e/d/;
                    print OUT "\tinsink($iclus) = $str_temp\t! input sink of $label[$iclus]\n";
                }
			}
		}else{
			for($icol=0;$icol<=$#insink_only;$icol++){
				@columns=split(',',$insink_only[$icol]);
				if ($#columns!=1){
					die "Can't understand the special input sink $insink_only[$icol] - the format should be 'clust,number'.\n";
				}
				$valid = 1;
				($string1,$string2) = &determine_cluster_composition($columns[0]);
				@temp_array=@$string1;
				if($string2 ne '' || sum(@temp_array)>sum(@temp_array[@mol_types_used[1..$nmol_types_used]])){
					# cluster contains molecule types not included in the system
					$valid = 0;
				}
				if(!$valid){
					die "Special input sink cluster $columns[0] is not a valid cluster\n";
				}
				if($nmol_types_used>1){
					$iclus = "clust_from_indices(".join(',',@temp_array[@mol_types_used[1..$nmol_types_used]]).")";
				}else{
					$imol=1;
					$iclus = $temp_array[$mol_types_used[$imol]];
				}
				$string1 = sprintf('%.14e',$columns[1]);
				$string1 =~ s/e/d/;
                print OUT "\tinsink($iclus) = $string1\n";
			}
            print OUT "\n";
		}
	}
    
}

if($lfortran && $l_use_get_losses){
	if($lloop){
		$str_temp = $lines{'inp'};
		$str_temp =~ s/,/+/;
		print OUT "\tloss = $str_temp\n";
	}
	print OUT "\nend subroutine get_losses$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
}

################################################################################
################################################################################
##   10. Collision rates                                                      ##
################################################################################
################################################################################

if($lfortran){
	if($l_coll_factor_mcmc_any){
		$icoef_coll=0;
	}
	if($l_evap_factor_mcmc){
		$icoef_evap=0;
	}
	print OUT "subroutine get_coll$append_to_eq_names(";
	if($lloop){
		print OUT "nrates,";
	}
	print OUT "K";
	if($l_mcmc_any){
		print OUT ",coef";
	}elsif($variable_temp){
		print OUT ",temperature";
	}
	print OUT ")\n\timplicit none\n";
	print OUT "\tinteger, parameter :: nclust = $max_cluster_number\n";
	if($lloop){
		print OUT "\treal(kind(1.d0)) :: K(nrates,nrates)";
	}else{
		print OUT "\treal(kind(1.d0)) :: K(nclust,nclust)";
	}
	if($l_mcmc_any){
		print OUT ", coef($n_mcmc_coefs)";
	}elsif($variable_temp){
		print OUT ", temperature";
	}
	print OUT "\n";
	if(!$lloop){
		print OUT "\n\t! collision coefficients\n\n";
		print OUT "\tK = 0.d0\n";
	}
}else{
	open(COLL, ">get_coll$append_to_file_names.m");
	if($variable_temp){
		print COLL "function K = get_coll(temperature)\n\n";
	}
	print COLL "% Collision coefficients\n\n";
	print COLL "K = nan($max_cluster_number,$max_cluster_number);\n\n";
}

################################################################################
################################################################################
##      10.1 Reading in rates for specific collisions                         ##
################################################################################
################################################################################

if($collision_coef_file_name ne ''){
    if(!$lsilent){
        print "\nCollision rate file: $collision_coef_file_name\n";
    }
	open(COLLISION, "<$collision_coef_file_name") || die "\nCould not open collision rate file $collision_coef_file_name\n\n";
	chomp(@temp_array=<COLLISION>);
	close(COLLISION);
	$number_of_lines=$#temp_array;
	$iline2 = 0;
	for($iline=0;$iline<=$number_of_lines;$iline++){
		next if ($temp_array[$iline] =~ /^\#/);
		if($temp_array[$iline] =~ /(\d+$name_water-?\d+)|(\d+$name_water\s*$)/){
			die "$collision_coef_file_name: Collision rate cannot be given for hydrates for now (if hydrate averaging is used, the given rate for dry clusters is taken to be the effective rate)";
		}
		@columns=split(' ',$temp_array[$iline]);			
		die "\n$columns[0] on line $iline in file $collision_coef_file_name should be a number\n\n" if (!&is_pos_number($columns[0]));
		die "\nThere should be three columns on line $iline in file $collision_coef_file_name: the rate and the two collision parties\n\n" if ($#columns != 2);
		$collision_coef_in[$iline2][0] = $columns[0];
		push(@{ $collision_coef_in[$iline2] },$columns[1]);
		push(@{ $collision_coef_in[$iline2] },$columns[2]);
		$iline2++;
	}
}

################################################################################
################################################################################
##      10.2 Reading in sticking factors                                      ##
################################################################################
################################################################################

if(($sticking_factor[0][0] == 1) && ($sticking_factor[1][0] == 1) && ($sticking_factor_file_name eq '')){
	$l_sticking_factor = 0;
}else{
	$l_sticking_factor = 1;
	if($sticking_factor[1][0] != 1){
		if($sticking_factor[0][0] == 1){
			$temp_val = $sticking_factor[1][0];
			@sticking_factor = ();
			$sticking_factor[0][0] = $temp_val;
			$sticking_factor[0][1] = 'ion-neutral';
		}else{
			$sticking_factor[1][0] = $sticking_factor[1][0];
			$sticking_factor[1][1] = 'ion-neutral';
		}
	}elsif($sticking_factor[0][0]){
		$temp_val = $sticking_factor[0][0];
		@sticking_factor = ();
		$sticking_factor[0][0] = $temp_val;
	}else{
		@sticking_factor = ();
	}
	if($lfortran && !$lloop){
		print OUT "\t! Using sticking factors that are visible in front of the collision coefficients\n";
	}elsif(!$lfortran){
		print COLL "% Using sticking factors that are visible in front of the collision coefficients\n";
	}
	if($sticking_factor_file_name ne ''){
        if(!$lsilent){
            print "\nSticking factor file: $sticking_factor_file_name\n";
        }
		open(STICKING, "<$sticking_factor_file_name") || die "\nCould not open sticking factor file $sticking_factor_file_name\n\n";
		chomp(@temp_array=<STICKING>);
		close(STICKING);
		$number_of_lines=$#temp_array;
		$iline2 = $#sticking_factor+1;
		for($iline=0;$iline<=$number_of_lines;$iline++){
			next if ($temp_array[$iline] =~ /^\#/);
			@columns=split(' ',$temp_array[$iline]);			
			die "\n$columns[0] on line $iline in file $sticking_factor_file_name should be a number\n\n" if (!&is_pos_number($columns[0]));
			$sticking_factor[$iline2][0] = $columns[0];
			if($#columns>0){
				push(@{ $sticking_factor[$iline2] },$columns[1]);
				if($#columns>1){
					push(@{ $sticking_factor[$iline2] },$columns[2]);
				}
			}
			$iline2++;
		}
	}
}

################################################################################
################################################################################
##      10.3 Reading in dipole moments and polarizabilities                   ##
##           for collision enhancement factors                                ##
################################################################################
################################################################################

if($include_ion_terms){
	# The Su73 and Su82 ion collision parameterizations require dipole moments and polarizabilities
	# but if all ion collisions have mcmc collision rates, the data is not obligatory.
	if($ion_coll_method =~ /Su73/i || $ion_coll_method =~ /Su82/i && !(!$dip_file_name && $l_coll_factor_mcmc_n_i && ($l_coll_factor_mcmc_n_g || (!$include_generic_neg && !$include_generic_pos)))){
		if(!$dip_file_name){
			die "\nYou didn't give dipole data file name!\n\n";
		}
		
		# Checking whether the energy and dipole files seem to belong together if both are used
		if(!$disable_evap || $lhydrate_average){
			# Do they have similar names?
			if(length($dip_file_name)>8 && length($free_energy_file_name)>8 && (substr($dip_file_name,-8) ne substr($free_energy_file_name,-8))){
				# Were they last modified within an hour of each other?
				if(abs((stat($dip_file_name))[9]-(stat($free_energy_file_name))[9])/3600>1){
					print "!!!!! Warning: do your energy and dipole files belong together? !!!!!\n";
				}
			}
		}
		

		# read in the dipole moments (D) and polarizabilities (Å^3)
		open(DIP, "<$dip_file_name") || die "\nCould not open dipole file $dip_file_name\n\n";
		chomp(@dip_data=<DIP>);
		close(DIP);
		$number_of_lines=$#dip_data+1;
		$iline0 = 0;
		# first two lines have the dipole locking coefficient for monomers and clusters in Su 73 method
		if(&is_pos_number($dip_data[0])){
			$c_mon=$dip_data[0];
			if ($c_mon < 0 || $c_mon > 1){
				die "\nDipole locking coefficients in $dip_file_name have to be in the range [0,1].\n\n";
			}
			$iline0++;
		}elsif($ion_coll_method =~ /Su73/i){
			die "\nFirst line of $dip_file_name has to be the dipole locking coefficient for monomers.\n\n";
		}
		if(&is_pos_number($dip_data[1])){
			$c_clust=$dip_data[1];
			if ($c_clust < 0 || $c_clust > 1){
				die "\nDipole locking coefficients in $dip_file_name have to be in the range [0,1].\n\n";

			}
			$iline0++;
		}elsif($ion_coll_method =~ /Su73/i){
			die "\nSecond line of $dip_file_name has to be the dipole locking coefficient for clusters\n\n";
		}
		for($iline=$iline0;$iline<$number_of_lines;$iline++){
			next if ($dip_data[$iline] =~ /^\#/);

			if($dip_data[$iline] =~ /^\s*(\S+)/){

				$temp_label=$1;
				
				# Checking if we have the cluster (or the corresponding dry one 
				# if we are using hydrates) in the system
				($iclus,$nwaters)=&get_corresponding_dry($temp_label);
				
				# save the dipole data if we have the cluster in the system
				if($iclus ne ''){
					# Each cluster must appear only once in the file, so the values should not be defined yet
					if(exists $dip_hydr[$iclus][$nwaters]){
						die "Diple data of cluster $temp_label is multiply defined in the file $dip_file_name.\n";
					}
					# there should be two values
					if($dip_data[$iline] =~ /^\s*(\S+)\s+(\S+)\s+(\S+)\s*/){
						$temp_val = $2;
						$temp_val2 = $3;
						if($ion_coll_method =~ /Su73/i){
							if($lmonomer[$iclus]){
								$temp_val *= $c_mon;
							}else{
								$temp_val *= $c_clust;
							}
						}
						if($nwaters==0){
							$dip[$iclus] = $temp_val;
							$pol[$iclus] = $temp_val2;
						}
						$dip_hydr[$iclus][$nwaters] = $temp_val;
						$pol_hydr[$iclus][$nwaters] = $temp_val2;
					}else{
						die "\nCouldn't read dipole moment and polarizability for $label in $dip_file_name.\n\n";
					}
				}
			}
		}

		# now all the clusters should have a dipole moment and polarizability values
		for($iclus=1;$iclus <= $max_cluster;$iclus++){
			next if($iclus==$n_flux_out || $iclus==$n_flux_out_neg || $iclus==$n_flux_out_pos);
			if($lneutral_cluster[$iclus]){
				for($ihydr=0;$ihydr<=$#{ $distr[$iclus] };$ihydr++){
					if(!(exists $dip_hydr[$iclus][$ihydr])){
						if($ihydr==0){
							die "\nDipole data not found in $dip_file_name for $label[$iclus].\n\n";
						}else{
							die "\nDipole data not found in $dip_file_name for $label[$iclus]$ihydr$name_water.\n\n";
						}
					}
				}
			}
		}
	}
}

################################################################################
################################################################################
##      10.4 Calculating the collision rates                                  ##
################################################################################
################################################################################

$missing_fcr = 0;

# This is just to go through the collision rate loop once
if($lloop){
	$n_flux_out_max = 1;
	$ind_quad_loss[1][0] = 1;
	$ind_quad_loss[1][1] = 1;
	$ind_quad_loss[1][2] = 1;
}

# Looping through the possible collisions
for($iclus=1;$iclus<=$n_flux_out_max;$iclus++){
	$lsame = 0;
	for($i=1;$i<=2*$ind_quad_loss[$iclus][0];$i+=2){
		$jclus = $ind_quad_loss[$iclus][$i];
		$kclus = $ind_quad_loss[$iclus][$i+1];
		
		# In the fortran version collisions of identical clusters are listed twice, 
		# but we only want to print the collision rates once here
		if($iclus==$jclus){
			if($lsame){
				$lsame = 0;
				next;
			}else{
				$lsame = 1;
			}
		}
		# Also collisions of different clusters need to be printed only once
		if(!$lloop && $jclus!=$n_flux_out && $jclus!=$n_flux_out_neg && $jclus!=$n_flux_out_pos && $iclus<$jclus){
			next;
		}
		
		$iclus_label=$label[$iclus];
		$jclus_label=$label[$jclus];
		
################################################################################
################################################################################
##         10.41 Determining if this collision has been given                 ##
##               a fixed rate value in the collision rate file                ##
################################################################################
################################################################################

		$lcoll_coef_in[$iclus][$jclus] = 0;
		
		if($collision_coef_file_name ne ''){
			for($iline=0;$iline<=$#collision_coef_in;$iline++){
				if((&compare_clusters($iclus_label,$collision_coef_in[$iline][1]) && &compare_clusters($jclus_label,$collision_coef_in[$iline][2])) || (&compare_clusters($jclus_label,$collision_coef_in[$iline][1]) && &compare_clusters($iclus_label,$collision_coef_in[$iline][2]))){
					$lcoll_coef_in[$iclus][$jclus] = 1;
					$coll_coef[$iclus][$jclus] = $collision_coef_in[$iline][0];
					last;
				}
			}
		}
		
		if($lcoll_coef_in[$iclus][$jclus] && !$lloop){
			
			$coll_coef_eff[$iclus][$jclus] = $coll_coef[$iclus][$jclus];
			$coll_coef_hydr[$iclus][$jclus][0][0] = $coll_coef[$iclus][$jclus]; # this is for calculating the evaporation rate, if it's not given as input
			$sticking_coef[$iclus][$jclus]="";
			$sticking_coef[$jclus][$iclus]="";
			
			if($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus]==1){
				$fcr[$iclus][$jclus] = 1;
				$fcr_hydr[$iclus][$jclus][0][0] = 1; # this is for calculating the evaporation rate, if it's not given as input
			}
		
################################################################################
################################################################################
##         10.42 Printing a function for calculating                          ##
##               the collision rate when using loops                          ##
################################################################################
################################################################################

			
		}elsif($lloop){
			print OUT "\treal(kind(1.d0)) :: ri, rj, mi, mj\n";
			if($loop_coll_coef =~ m/^Dahneke$/i){
				print OUT "\treal(kind(1.d0)) :: Di, Dj, vthi, vthj, Kn\n";
			}
			print OUT "\tinteger :: nrates, i, j\n";
			if($nmol_types_used>1){
				print OUT "\tinteger, save :: nclust_inc=0, indices(nclust,$nmol_types_used)\n\n";
				print OUT "\tif (nclust_inc .eq. 0) then\n";
				print OUT "\t\tcall get_molecule_numbers$append_to_eq_names(nclust_inc,indices)\n";
				print OUT "\tend if\n";
			}
			print OUT "\n";
			print OUT "\tK = 0.d0\n\n";
			print OUT "\tdo i = 1,$nclust_included\n";
			if($nmol_types_used>1){
				print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(mi,ri,indices(i,:))\n";
				print OUT "\t\tdo j = i,$nclust_included\n";
				print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mj,rj,indices(j,:))\n";
			}else{
				print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(mi,ri,i)\n";
				print OUT "\t\tdo j = i,nclust\n";
				print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(mj,rj,j)\n";
			}
			
			if($loop_coll_coef =~ m/^hard_spheres$/i){
				# Hard-sphere collision rate
				$temp_val = 8*$pi*$boltz/$mass_conv;
				if(!$variable_temp){
					$temp_val *= $temperature;
				}
				$string1 = sprintf('%.14e',$temp_val);
				$string1 =~ s/e/d/;
				if(!$variable_temp){
					print OUT "\t\t\tK(i,j) = sqrt($string1*(1.d0/mi+1.d0/mj))*(ri+rj)**2.d0\n";
				}else{
					print OUT "\t\t\tK(i,j) = sqrt($string1*temperature*(1.d0/mi+1.d0/mj))*(ri+rj)**2.d0\n";
				}
			}elsif($loop_coll_coef =~ m/^Dahneke$/i){
				if($variable_temp){
					die "\nVariable temperature not implemented for the Dahneke parameterization.\n\n";
				}
				# Collision rate parameterization by Dahneke (1983) with a non-continuum correction
				# Seinfeld and Pandis, 2nd edition, chapters 9, 12 and 13
				$air_viscosity = 2.5277e-7*$temperature**0.75302; # from DMAN
				# mean free path of air from S&P Eq. 9.6, assuming standard pressure
				$string1 = sprintf('%.14e',2*$air_viscosity/(101325*sqrt(8*0.0289/($pi*$Na*$boltz*$temperature))));
				$string1 =~ s/e/d/;
				# diffusivities
				# S&P Eq. 9.73, but don't know where the factor (Cc?) with the Kn term comes from (it is like this in DMAN)
				$string2 = sprintf('%.14e',$boltz*$temperature/(3*$pi*$air_viscosity));
				$string2 =~ s/e/d/;
				# factor for the thermal velocities
				$string3 = sprintf('%.14e',8*$boltz*$temperature/$pi/$mass_conv);
				$string3 =~ s/e/d/;
				$string4 = sprintf('%.14e',$pi);
				$string4 =~ s/e/d/;
				
				# For comparisons with DMAN/TOMAS, coefficients for collisions involving an acid or ammonia monomer are calculated in a different way
				# -> uncomment the following block if you want to use this feature
				# Note that when two monomers collide, one of them is treated as a molecule and one as a particle (for mathematical consistency)
				# if('A' ~~ @molecule_name[@mol_types_used[1..$nmol_types_used]] || 'N' ~~ @molecule_name[@mol_types_used[1..$nmol_types_used]]){
					# print "Applying the DMAN condensation coefficients to collisions involving monomers A and N.\n\n";					
					# if($nmol_types_used>1){
					    # die "Add this if you need it; don't have time to fix these stupidities now.\n";
						# #print OUT "\t\t\tif(sum(indices(i,:)) .eq. 1 .and. sum(indices(j,:)) .eq. 1) then\n";
						# #print OUT "\t\t\tend if\n";
					# }else{
						# print OUT "\t\t\tif(i .eq. 1) then\n";
						# # gas diffusivity in air from gasdiff.f, assuming standard pressure
						# $str_temp = sprintf('%.14e',1e-7*$temperature**1.75/101325*1e5/(42.88**(1/3)+20.1**(1/3))**2);
						# $str_temp =~ s/e/d/;
						# print OUT "\t\t\t\tDi = $str_temp*sqrt((mi+28.9d0)/(mi*28.9d0))\n";
						# print OUT "\t\t\t\tKn = $string1/rj\n";
						# if($molecule_name[$mol_types_used[1]] eq 'A'){
							# # the so-called accommodation coefficient is 0.65 for acid
							# print OUT "\t\t\t\tK(i,j) = 4.d0*$string4*Di*rj*(1.d0+Kn)/(1.d0+2.d0*Kn*(1.d0+Kn)/0.65)\n";
						# }else{
							# die "You have a one-component system, but the component is not acid (A)??\n";
						# }
						# print OUT "\t\t\telse\n";
					# }
					# $str_temp = "\t";
					# $str_temp2 = "\t\t\tend if\n";
				# }else{
					# $str_temp = "";
					# $str_temp2 = "";
				# }
				$str_temp = "";
				$str_temp2 = "";
				
				print OUT "$str_temp\t\t\tDi = $string2/(2.d0*ri)*((5.d0+4.d0*($string1/ri)+&\n\t\t\t\t& 6.d0*($string1/ri)**2.d0+18.d0*($string1/ri)**3)/&\n\t\t\t\t& (5.d0-($string1/ri)+(8.d0+$string4)*($string1/ri)**2.d0))\n";
				print OUT "$str_temp\t\t\tDj = $string2/(2.d0*rj)*((5.d0+4.d0*($string1/rj)+&\n\t\t\t\t& 6.d0*($string1/rj)**2.d0+18.d0*($string1/rj)**3)/&\n\t\t\t\t& (5.d0-($string1/rj)+(8.d0+$string4)*($string1/rj)**2.d0))\n";
				print OUT "$str_temp\t\t\tvthi = sqrt($string3/mi)\n";
				print OUT "$str_temp\t\t\tvthj = sqrt($string3/mj)\n";
			    # S&P eqn 12.35 with the relative velocity
				print OUT "$str_temp\t\t\tKn = 2.d0*(Di+Dj)/(sqrt(vthi**2.d0+vthj**2.d0)*(ri+rj))\n";
                # S&P Eq. 13.50 with a non-continuum correction beta as in S&P Table 12.1
                print OUT "$str_temp\t\t\tK(i,j) = 4.d0*$string4*(ri+rj)*(Di+Dj)*(1.d0+Kn)/(1.d0+2.d0*Kn*(1.d0+Kn))\n";
				
				print OUT $str_temp2;
				
			}else{
				die "\nCan't understand collision coefficient definition $loop_coll_coef.\n\n";
			}
				
			print OUT "\t\t\tK(j,i) = K(i,j)\n";
			print OUT "\t\tend do\n";
			print OUT "\tend do\n\n";
			if($sticking_factor[0][0]!=1){
				print OUT "\t! sticking/enhancement factor\n";
				print OUT "\tK = $sticking_factor[0][0]*K\n\n";
			}
		
################################################################################
################################################################################
##         10.43 Calculating the hard sphere collision rate                   ##
################################################################################
################################################################################

		}else{
		
			@distr_temp = @{$distr[$iclus]};
			@distr_temp2 = @{$distr[$jclus]};
		
			# This will be the effective collision rate summed over all hydrates
			$coll_coef_eff[$iclus][$jclus]=0.0;
#print "\n";
		
			for($ihydr=0;$ihydr<=$#distr_temp;$ihydr++){
				if($ihydr != 0){
					$temp_label=$iclus_label.$ihydr.$name_water;
				}else{
					$temp_label=$iclus_label;
				}
				for($jhydr=0;$jhydr<=$#distr_temp2;$jhydr++){
					if($jhydr != 0){
						$temp_label2=$jclus_label.$jhydr.$name_water;
					}else{
						$temp_label2=$jclus_label;
					}
				
					if(defined $distr_temp[$ihydr] && defined $distr_temp2[$jhydr]){
					
						# If the clusters are ions with opposite charge, we'll use a constant recombination coefficient
						if(($lnegative[$iclus]&&$lpositive[$jclus]) || ($lpositive[$iclus]&&$lnegative[$jclus])){
							$coll_coef_hydr[$iclus][$jclus][$ihydr][$jhydr] = $recomb_coeff;
							$coll_coef_eff[$iclus][$jclus] = $recomb_coeff;
							next;
					
						# Otherwise calculate the collision coefficient from kinetic gas theory
						# Ion-neutral collision enhancement factors are done later
						}else{
							$mass1=$clust_mass[$iclus][$ihydr];
							$mass2=$clust_mass[$jclus][$jhydr];

							$r1=$clust_radius[$iclus][$ihydr];
							$r2=$clust_radius[$jclus][$jhydr];
#print "mass($label[$iclus]$ihydr" . "$name_water)=$mass1\n";
#print "mass($label[$jclus]$jhydr" . "$name_water)=$mass2\n";
#print "$label[$jclus]$jhydr" . "$name_water: $lhas_hydr[$jclus],$#distr_temp2, @distr_temp2\n\n";
							$coll_coef_temp=(8.0*$pi*$boltz*$temperature)**0.5;
							$coll_coef_temp*=(1.0/$mass1+1.0/$mass2)**0.5;
							$coll_coef_temp*=($r1+$r2)**2;
							
							$coll_coef_hydr[$iclus][$jclus][$ihydr][$jhydr] = $coll_coef_temp;
						}
#print "+$distr_temp[$ihydr]*$distr_temp2[$jhydr]*$coll_coef_temp ";
						if($lneutral_cluster[$iclus] && $lneutral_cluster[$jclus]){
							# Neutral-neutral collision rate, weighted with the hydrate distributions
							$coll_coef_eff[$iclus][$jclus] += $distr_temp[$ihydr]*$distr_temp2[$jhydr]*$coll_coef_temp;
							next;
						}
#						a1=.0757; a3=.0015; b0=.0151;b1=-.186;b3=-.0163;
#					for i=1:length(n), for j=i:length(n), AA=6.4e-20/kB/T*4*r(i)*r(j)/(r(i)+r(j))^2; E(i,j)=1+sqrt(AA/3)/(1+b0*sqrt(AA))+b1*log(1+AA)+b3*(log(1+AA))^3; fprintf(fid,'%.14g\t%8s\t%8s\n',E(i,j),[num2str(i),'Ad'],[num2str(j),'Ad']); end, end
################################################################################
################################################################################
##      10.5 Calculating the ion collision enhancement factors                ##
################################################################################
################################################################################

						# Now we have left only the cases with one ion and one neutral. Which is the neutral one?
						if($lneutral_cluster[$iclus]){
							$nclus = $iclus;
							$nhydr = $ihydr;
						}else{
							$nclus = $jclus;
							$nhydr = $jhydr;
						}
					
################################################################################
################################################################################
##         10.51 Su and Bowers, 1973                                          ##
################################################################################
################################################################################
		
						if($ion_coll_method =~ /Su73/i){
							if(!defined($dip_hydr[$nclus][$nhydr])){
								$fcr_temp = -1;
								$missing_fcr += 1;
							}elsif(!$variable_temp){
								$fcr_temp = 9.5436e-29*sqrt($pol_hydr[$nclus][$nhydr])+6.4805e-27*$dip_hydr[$nclus][$nhydr]/sqrt($temperature);
								$fcr_temp *= sqrt(1./$mass1+1./$mass2);
								$fcr_temp /= $coll_coef_temp;
								if($fcr_temp < 1){
									$fcr_temp = 1;
								}
							}else{
								$fcr_temp = sprintf('%.14e',9.5436e-29*sqrt($pol_hydr[$nclus][$nhydr])*sqrt(1./$mass1+1./$mass2));
								$str_temp = sprintf('%.14e',6.4805e-27*$dip_hydr[$nclus][$nhydr]*sqrt(1./$mass1+1./$mass2));
								if($lfortran){
									$fcr_temp =~ s/e/d/;
									$str_temp =~ s/e/d/;
								}
								$fcr_temp = "($fcr_temp+$str_temp/sqrt(temperature))";
							}
					
################################################################################
################################################################################
##         10.52 Su and Chesnavich, 1982                                      ##
################################################################################
################################################################################
		
						}elsif($ion_coll_method =~ /Su82/i){
							if(!defined($dip_hydr[$nclus][$nhydr])){
								$fcr_temp = -1;
								$missing_fcr += 1;
							}elsif(!$variable_temp){

								$fcr_temp = 100.*$dip_hydr[$nclus][$nhydr]/sqrt(2.*$pol_hydr[$nclus][$nhydr]*$boltz*1.e23*$temperature);
								if($fcr_temp<2){
									$fcr_temp = ($fcr_temp+0.5090)**2/10.526+0.9754;
								}else{
									$fcr_temp = 0.4767*$fcr_temp+0.62;
								}
								$fcr_temp *= 2.*$pi*4.8032e-16*sqrt($pol_hydr[$nclus][$nhydr]*(1./$mass1+1./$mass2)/1.e27);
								$fcr_temp /= $coll_coef_temp;
								if($fcr_temp < 1){
									$fcr_temp = 1;
								}
							}elsif($lfortran){
								$temp_val = sprintf('%.14e',(50.*$dip_hydr[$nclus][$nhydr])**2/(2.*$pol_hydr[$nclus][$nhydr]*$boltz*1.e23));
								$temp_val =~ s/e/d/;
								$fcr_temp = "(.5d0+sign(.5d0,temperature-$temp_val))&\n\t\t&";
								$str_temp = "(.5d0-sign(.5d0,temperature-$temp_val))&\n\t\t&";
								$temp_val = sprintf('%.14e',100.*$dip_hydr[$nclus][$nhydr]/sqrt(2.*$pol_hydr[$nclus][$nhydr]*$boltz*1.e23));
								$temp_val =~ s/e/d/;
								$fcr_temp .= "*(($temp_val/sqrt(temperature)+0.5090d0)**2.d0/10.526d0+0.9754d0)";
								$str_temp .= "*(0.4767d0*$temp_val/sqrt(temperature)+0.62d0)";
								$temp_val = sprintf('%.14e',2.*$pi*4.8032e-16*sqrt($pol_hydr[$nclus][$nhydr]*(1./$mass1+1./$mass2)/1.e27));
								$temp_val =~ s/e/d/;
								$fcr_temp = "(&\n\t\t&$fcr_temp&\n\t\t&+$str_temp)&\n\t\t&*$temp_val";
							}else{
								$temp_val = sprintf('%.14e',(50.*$dip_hydr[$nclus][$nhydr])**2/(2.*$pol_hydr[$nclus][$nhydr]*$boltz*1.e23));
                                $fcr_temp = "max(sign(temperature-$temp_val),0)";
								$str_temp = "max(sign($temp_val-temperature),0)";
								$temp_val = sprintf('%.14e',100.*$dip_hydr[$nclus][$nhydr]/sqrt(2.*$pol_hydr[$nclus][$nhydr]*$boltz*1.e23));
								$fcr_temp .= "*(($temp_val/sqrt(temperature)+0.5090)^2/10.526+0.9754)";
								$str_temp .= "*(0.4767*$temp_val/sqrt(temperature)+0.62)";
								$temp_val = sprintf('%.14e',2.*$pi*4.8032e-16*sqrt($pol_hydr[$nclus][$nhydr]*(1./$mass1+1./$mass2)/1.e27));
								$fcr_temp = "(...\n\t$fcr_temp...\n\t+$str_temp)...\n\t*$temp_val";
							}

################################################################################
################################################################################
##         10.53 Constant enhancement for all collisions                      ##
################################################################################
################################################################################

						}elsif($ion_coll_method =~ m/constant/i){
							if(!$variable_temp){
								$fcr_temp = 10.0;
							}elsif($lfortran){
								$fcr_temp = "10.d0";
							}else{
								$fcr_temp = "10.0";
							}
						}else{
							die "Error: trying to use undefined ion collision method $ion_coll_method.\n";
						}
					
################################################################################
################################################################################
##      10.6 Hydrate averaged collision rate including ion enhancement        ##
################################################################################
################################################################################

						$fcr_hydr[$iclus][$jclus][$ihydr][$jhydr] = $fcr_temp;
						if(!$lhydrate_average){
							$fcr[$iclus][$jclus] = $fcr_temp;
						}else{
							$fcr[$iclus][$jclus] = '';
							# Collision rate with ion enhancement factor, weighted with the hydrate distributions
							if($coll_coef_eff[$iclus][$jclus]>=0 && $fcr_temp>=0){
								$coll_coef_eff[$iclus][$jclus] += $distr_temp[$ihydr]*$distr_temp2[$jhydr]*$coll_coef_temp*$fcr_temp;
							}else{
							# This is for an MCMC simulation where dipole data is missing for some hydrate
								$coll_coef_eff[$iclus][$jclus] = -1;
							}
						}
					}
				}
			}
			if(!$lhydrate_average){
				$coll_coef[$iclus][$jclus] = $coll_coef_hydr[$iclus][$jclus][0][0];
			}

################################################################################
################################################################################
##      10.7 Figuring out sticking factors for each collision                 ##
################################################################################
################################################################################

			if($l_sticking_factor == 1){
				$temp_val = 1.0;
				for($iline=0;$iline<=$#sticking_factor;$iline++){
					if($#{ $sticking_factor[$iline] } == 0 || $sticking_factor[$iline][1] ~~ @molecule_name){
						# if only one sticking factor (and molecule type) is given, 
						# using it only for neutral-neutral collisions
						if($lneutral_cluster[$iclus] && $lneutral_cluster[$jclus]){
							if($#{ $sticking_factor[$iline] } == 0){
								$temp_val = $sticking_factor[$iline][0];
							}elsif($iclus_label =~ /\d+$sticking_factor[$iline][1]\d+/ || $iclus_label =~ /\d+$sticking_factor[$iline][1]$/ || $jclus_label =~ /\d+$sticking_factor[$iline][1]\d+/ || $jclus_label =~ /\d+$sticking_factor[$iline][1]$/){
								$temp_val = $sticking_factor[$iline][0];
							}
						}
					# next option: this is a sticking factor for all ion-neutral collisions
					}elsif($#{ $sticking_factor[$iline] } == 1 && $sticking_factor[$iline][1] eq 'ion-neutral'){
						if($lneutral_cluster[$iclus] + $lneutral_cluster[$jclus] == 1){
							$temp_val = $sticking_factor[$iline][0];
						}
					# if the sticking factor is defined for specific collisions
					}elsif(&compare_clusters($iclus_label,$sticking_factor[$iline][1]) || &compare_clusters($jclus_label,$sticking_factor[$iline][1])){
						if($#{ $sticking_factor[$iline] } == 1){
							$temp_val = $sticking_factor[$iline][0];
						}else{
							if(&compare_clusters($iclus_label,$sticking_factor[$iline][1])){
								$wanted_clus=$jclus_label;
							}else{
								$wanted_clus=$iclus_label;
							}
							if(&compare_clusters($wanted_clus,$sticking_factor[$iline][2])){
								$temp_val = $sticking_factor[$iline][0];
							}
						}
					}
				}
				if($temp_val != 1.){
					$temp_val=sprintf('%.4e',$temp_val);
					if($lfortran){
						$temp_val =~ s/e/d/;
					}
					$sticking_coef[$iclus][$jclus]="$temp_val*";
				}else{
					$sticking_coef[$iclus][$jclus]="";
				}
				$sticking_coef[$jclus][$iclus]=$sticking_coef[$iclus][$jclus];
			}else{
				$sticking_coef[$iclus][$jclus]="";
				$sticking_coef[$jclus][$iclus]="";
			}
		
################################################################################
################################################################################
##      10.8 Checking if this is an MCMC coefficient                          ##
################################################################################
################################################################################
		
			$l_mcmc_coef = 0;
			if($l_coll_factor_mcmc_all){
				$l_mcmc_coef = 1;
			}elsif($l_coll_factor_mcmc_n_n && $lneutral_cluster[$iclus] && $lneutral_cluster[$jclus]){
				$l_mcmc_coef = 1;
			}elsif($l_coll_factor_mcmc_n_i && ($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus] == 1)){
				$l_mcmc_coef = 1;
			}elsif($l_coll_factor_mcmc_n_g && $lneutral_cluster[$iclus] && $jclus>$max_cluster){
				$l_mcmc_coef = 1;
			}elsif($l_coll_factor_mcmc_n_g && $lneutral_cluster[$jclus] && $iclus>$max_cluster){
				$l_mcmc_coef = 1;
			}elsif($l_coll_factor_mcmc_rec && !$lneutral_cluster[$iclus] && !$lneutral_cluster[$jclus]){
				$l_mcmc_coef = 1;
			}
			if($l_mcmc_coef){
				$icoef_coll+=1;
			}
		
		}
				
################################################################################
################################################################################
##      10.9 Printing out the collision rates                                 ##
################################################################################
################################################################################
		
		$value_string = "";
		$coll_string = "$iclus_label + $jclus_label";
		$fixed_string = "";
		$fcr_string = "";
		$hydr_string = "";
		
		if(!$lloop && $lcoll_coef_in[$iclus][$jclus]){
		
			$fixed_string = ", collision rate given as input";
			$value_string = sprintf('%.14e',$coll_coef[$iclus][$jclus]);
			if($lfortran){
				$value_string =~ s/e/d/;
			}
		
		}elsif(!$lloop){
		
			# When using hydrates, print also the corresponding dry value (FCR & collision coefficient) for comparison.
			if($lhydrate_average){
				if($lhas_hydr[$iclus] || $lhas_hydr[$jclus]){
					if($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus] == 1){
						$hydr_string = ", dry value: " . sprintf('%.14e',$fcr_hydr[$iclus][$jclus][0][0]*$coll_coef_hydr[$iclus][$jclus][0][0]) . ", including ion enhancement " . sprintf('%.3g',$fcr_hydr[$iclus][$jclus][0][0]) . "*" . sprintf('%.2e',$coll_coef_hydr[$iclus][$jclus][0][0]);
					}else{
                        if(defined $distr[$iclus][0] && defined $distr[$jclus][0]){
                            $hydr_string = ", dry value: " . sprintf('%.14e',$coll_coef_hydr[$iclus][$jclus][0][0]);
                        }else{
                            $hydr_string = ", dry value undefined";
                        }
					}
					if($sticking_coef[$iclus][$jclus] ne ''){
						$hydr_string = "$hydr_string (sticking coef.  $sticking_coef[$iclus][$jclus])";
					}
				}else{
					$hydr_string = ", no hydrates";
				}
				$value_string = sprintf('%.14e',$coll_coef_eff[$iclus][$jclus]);
				if($lfortran){
					$value_string =~ s/e/d/;
				}
			}else{
				# When using variable_temp, take the T dependence out of the collision rate (not for recombination)
				if($variable_temp && ($lneutral_cluster[$iclus] || $lneutral_cluster[$jclus])){
				
					$str_temp = sprintf('%.14e',$coll_coef[$iclus][$jclus]/$temperature**0.5);
					if($lfortran){
						$str_temp =~ s/e/d/;
					}
					$str_temp = "$str_temp*sqrt(temperature)"; # this is the bare hard-sphere collision rate
				
					if(($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus] == 1) && ($ion_coll_method !~ m/constant/i)){
						$value_string = "max($fcr[$iclus][$jclus],$str_temp)";
						$fcr_string = ", selecting the higher one of ionic rate and hard-sphere rate";
					}else{
						$value_string = $str_temp;
					}
					
				# Standard case: no hydrates and no visible temperature dependence
				}else{
					if($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus] == 1){
						$value_string = sprintf('%.14e',$fcr[$iclus][$jclus]*$coll_coef[$iclus][$jclus]);
						$fcr_string = ", including ion enhancement " . sprintf('%.3g',$fcr[$iclus][$jclus]) . "*" . sprintf('%.2e',$coll_coef[$iclus][$jclus]);
					}else{
						$value_string = sprintf('%.14e',$coll_coef[$iclus][$jclus]);
					}
					if($lfortran){
						$value_string =~ s/e/d/;
					}
				}
			}
			
			# Add a possible sticking coefficient
			$value_string = "$sticking_coef[$iclus][$jclus]$value_string";
			
		}
		
		if(!$lfortran){
			print COLL "K($iclus,$jclus) = $value_string;\t% $coll_string$fixed_string$fcr_string$hydr_string\n";
			print COLL "K($jclus,$iclus) = K($iclus,$jclus);\n" if($iclus != $jclus);
		}elsif(!$lloop){
			$string = "$value_string\t! $coll_string$fixed_string$fcr_string$hydr_string";
			if($l_mcmc_coef){
				# If this is an MCMC coefficient, save the true value to be printed later ...
				$coef_true[$icoef_coll] = $string;
				# ... and print here just the MCMC coefficient
				print OUT "\tK($iclus,$jclus) = coef($icoef_coll)\t! $coll_string\n";
			}else{
				print OUT "\tK($iclus,$jclus) = $string\n";
			}
			print OUT "\tK($jclus,$iclus) = K($iclus,$jclus)\n" if($iclus != $jclus);
		}
		
	}  # end of the jclus loop
}  # end of the iclus loop

if($lfortran){
	print OUT "\nend subroutine get_coll$append_to_eq_names\n\n!-----------------------------------------------------------\n\n";
}else{
	if($variable_temp){
		print COLL "\nend";
	}
	close(COLL);
}

################################################################################
################################################################################
##   11. Evaporation rates                                                    ##
################################################################################
################################################################################

if(!$lfortran){
	open(EVAP, ">get_evap$append_to_file_names.m");
	if($variable_temp){
		print EVAP "function E = get_evap(temperature,K)\n\n";
	}
}
$missing_energies = 0;
if(!$disable_evap){

	if($lfortran){
		print OUT "subroutine get_evap$append_to_eq_names(";
		if($lloop){
			print OUT "nrates,";
		}
		print OUT "E";
		if($l_mcmc_any){
			print OUT ",coef";
		}elsif($variable_temp){
			print OUT ",K,temperature";
		}
		print OUT ")\n";
		if($lloop && $nmol_types_used>1 && $loop_evap_coef =~ m/^Kelvin$/i){
			print OUT "use acdc_system$append_to_syst_names, only : monomer_indices$append_to_syst_names\n";
		}
		if($lhs_tests){
			print OUT "use acdc_hsdata$append_to_ext_names, only : get_hsdata$append_to_ext_names\n";
		}
		print OUT "\timplicit none\n";
		if(!$lloop){
			print OUT "\treal(kind(1.d0)) :: E($max_cluster_number,$max_cluster_number)";
			if($variable_temp){
				print OUT ", K($max_cluster_number,$max_cluster_number), temperature";
			}elsif($l_mcmc_any){
				print OUT ", coef(" . ($n_mcmc_coefs+$variable_cs+2*$variable_ion_source) . ")";
			}		
			print OUT "\n\n\t! evaporation coefficients\n";
			print OUT $evap_comment;
			print OUT "\n\tE = 0.d0\n";
		}
	}elsif(!$lfortran){
		print EVAP "% Evaporation coefficients\n";
		print EVAP $evap_comment;
		print EVAP "\nE = nan($max_cluster_number,$max_cluster_number);\n\n";
	}


################################################################################
################################################################################
##      11.1 Function for computing evaporation rates when using loops        ##
################################################################################
################################################################################

	if($lloop){
		print OUT "\tinteger, parameter :: nclust = $max_cluster_number";
		if($lloop_cs && $nmol_types_used>1){
			print OUT ", ij_ind_cs($nmol_types_used) = (/$nmol_cs_list/)";
		}
		print OUT "\n";
		print OUT "\treal(kind(1.d0)) :: E(nrates,";
		if($disable_nonmonomer_evaps && $nmol_types_used==1){
			print OUT "1)";
		}else{
			print OUT "nrates)";
		}
		print OUT ", K(nrates,nrates), temperature\n";
		if($nmol_types_used>1){
			print OUT "\tinteger, save :: nclust_inc=0, indices(nclust,$nmol_types_used), clust_from_indices($nmol_comp_list)\n";
		}
		print OUT "\treal(kind(1.d0)) :: m, r, xmol\n";
		print OUT "\tinteger :: nrates, ij_ind($nmol_types_used), i, j, ij, imol";
		if($lhs_tests){
			print OUT ", ind(2)\n";
			print OUT "\tlogical, save, allocatable :: lhs(:)\n";
			print OUT "\treal(kind(1.d0)), save, allocatable :: deltah(:), deltas(:)";
		}
		print OUT "\n";
		
		
		$temp_val = $boltz;
		if(!$variable_temp){
			$temp_val *= $temperature;
		}
		$string1 = sprintf('%.14e',$temp_val);
		$string1 =~ s/e/d/;
		if($variable_temp){
			$string1 = "($string1*temperature)";
		}
		
		$temp_val = $kcal_per_mol_to_J/$boltz;
		if(!$variable_temp){
			$temp_val /= $temperature;
		}
		$string2 = sprintf('%.14e',$temp_val);
		$string2 =~ s/e/d/;
		if($variable_temp){
			$string2 = "($string2/temperature)";
		}

################################################################################
################################################################################
##   11.11 Evaporation rates from DeltaGs                                     ##
################################################################################
################################################################################
		
		if($loop_evap_coef =~ m/^DeltaG$/i){
			# Evaporation coefficients via DeltaGs and detailed balance
			
			print OUT "\treal(kind(1.d0)) :: gi, gj, gij, p\n\n";
			if($nmol_types_used>1){
				print OUT "\tif (nclust_inc .eq. 0) then\n";
				print OUT "\t\tcall get_molecule_numbers$append_to_eq_names(nclust_inc,indices)\n";
				print OUT "\t\tcall get_cluster_numbers$append_to_eq_names(clust_from_indices)\n";
				print OUT "\tend if\n";
			}
			print OUT "\tE = 0.d0\n\n";

			if($variable_temp){
				print "\nVariable temperature not implemented in the cluster_energies input.\n\n";
			}else{
				print OUT "\tcall get_coll$append_to_eq_names(nrates,K)\n";
			}
			
			if($disable_nonmonomer_evaps && $nmol_types_used==1){
				if($lloop_cs){
					print OUT "\tdo i = 1,nclust-2\n";
				}else{
					print OUT "\tdo i = 1,nclust-1\n";
				}
				if($rlim_no_evap !~ /^\s*$/){
					print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,i+1)\n";
					print OUT "\t\tif(r .ge. $rlim_no_evap_str) then\n";
					print OUT "\t\t\texit\n";
					print OUT "\t\tend if\n";
				}
				print OUT "\t\tif (i .eq. 1) then\n";
				print OUT "\t\t\tcall cluster_energies$append_to_ext_names(gi,p,1,i)\n";
				print OUT "\t\t\tgj = gi\n";
				print OUT "\t\telse\n";
				print OUT "\t\t\tgi = gij\n";
				print OUT "\t\tend if\n";
				print OUT "\t\tcall cluster_energies$append_to_ext_names(gij,p,1,i+1)\n";
				print OUT "\t\tE(i,1) = K(i,1)*p/$string1*exp((gij-gi-gj)*$string2)\n";
				print OUT "\t\tif (i .eq. 1) then\n";
				print OUT "\t\t\tE(i,1) = .5d0*E(i,1)\n";
				print OUT "\t\tend if\n";
				print OUT "\tend do\n\n";
			}else{
				print OUT "\tdo i = 1,$nclust_included\n";
				if($nmol_types_used>1){
					print OUT "\t\tcall cluster_energies$append_to_ext_names(gi,p,$nmol_types_used,indices(i,:))\n";
				}else{
					print OUT "\t\tcall cluster_energies$append_to_ext_names(gi,p,1,i)\n";
				}
				print OUT "\t\tdo j = i,$nclust_included\n";
				if($nmol_types_used>1){
					print OUT "\t\t\tij_ind = indices(i,:)+indices(j,:)\n";
					if($rlim_no_evap !~ /^\s*$/){
						print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(m,r,ij_ind)\n";
						print OUT "\t\t\tif(r .ge. $rlim_no_evap_str) then\n";
						print OUT "\t\t\t\tcycle\n";
						print OUT "\t\t\tend if\n";
					}
					print OUT "\t\t\tif(clust_from_indices($nmol_ranges_ij_ind).gt.0";
					if($lloop_cs){
						print OUT " .and. .not.all(ij_ind .eq. ij_ind_cs)";
					}
					print OUT ") then\n";
					print OUT "\t\t\t\tij = clust_from_indices($nmol_ranges_ij_ind)\n";
					print OUT "\t\t\t\tcall cluster_energies$append_to_ext_names(gj,p,$nmol_types_used,indices(j,:))\n";
					print OUT "\t\t\t\tcall cluster_energies$append_to_ext_names(gij,p,$nmol_types_used,ij_ind)\n";
				}else{
					print OUT "\t\t\tij=i+j\n";
					if($rlim_no_evap !~ /^\s*$/){
						print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,ij)\n";
						print OUT "\t\tif(r .ge. $rlim_no_evap_str) then\n";
						print OUT "\t\t\texit\n";
						print OUT "\t\tend if\n";
					}
					print OUT "\t\t\tif(ij .le. nclust) then\n";
					print OUT "\t\t\t\tcall cluster_energies$append_to_ext_names(gj,p,1,j)\n";
					print OUT "\t\t\t\tcall cluster_energies$append_to_ext_names(gij,p,1,ij)\n";
				}
				print OUT "\t\t\t\tE(i,j) = K(i,j)*p/$string1*exp((gij-gi-gj)*$string2)\n";
				print OUT "\t\t\t\tif (i .eq. j) then\n";
				print OUT "\t\t\t\t\tE(i,j) = .5d0*E(i,j)\n";
				print OUT "\t\t\t\tend if\n";
				print OUT "\t\t\t\tE(j,i) = E(i,j)\n";
				print OUT "\t\t\tend if\n";
				print OUT "\t\tend do\n";
				print OUT "\tend do\n\n";
			}
			
################################################################################
################################################################################
##   11.12 Evaporation rates from the Kelvin formula                          ##
################################################################################
################################################################################
			
		}elsif($loop_evap_coef =~ m/^Kelvin$/i){
		    # No fissions, monomer evaporation according to the Kelvin equation
			# = an approximation based on liquid drop DeltaG and non-discrete cluster limit

			# Suggestions for values for parameters psat and sigma that produce evaporation frequencies of realistic orders of magnitude:
			# sigma is assumed to be temperature-independent and to correspond to the sulfuric acid value of 0.05 N/m
			# psat is assumed to be temperature-dependent, but the dependence is a very rough approximation, for now:
			# The parameters are set so that at 280 K, the value is 5e-11 Pa which produces evaporation rates around QC values for H2SO4 and NH3;
			# the functional form is psat=exp(A/T+B) for H2SO4 vapor pressure over solid ammonium sulfate from Marti et al., JGR 102, 3725-3735, 1997, 
			# in which A = -5928 (+-891) and B = -3.77 (+-2.69);
			# however, here B is set to B = -2.55 in order to produce the wanted values at 280 K (an often used temperature e.g. in CLOUD).
			#if($temperature == 280){
			#	$temp_val = 5e-11;
			#}else{
			#	$temp_val = exp(-5928/$temperature-2.55);
			#}
			#$string3 = sprintf('%.14e',$temp_val);
			#$string3 =~ s/e/d/; # psat
			
			print OUT "\tinteger, save :: n_monomers($nmol_types_used)\n";
			
			$str_temp = "";
			$str_temp2 = "";
			$str_temp3 = "";
			for($imol=1;$imol<=$nmol_types_used;$imol++){
				$str_temp .= sprintf('%.14e',$psat[$mol_types_used[$imol]]).",";
				$str_temp2 .= sprintf('%.14e',$mass[$mol_types_used[$imol]]/$density[$mol_types_used[$imol]]).",";
				if($imol==1){
					$sigma = $surface_tension[$mol_types_used[$imol]];
					$str_temp3 = sprintf('%.14e',$sigma);
				}else{
					if($surface_tension[$mol_types_used[$imol]] != $sigma){
						print "The surface tension is not the same for all compounds\n";
						print "-> Using the one for the first compound (no parameterization for a mixture implemented yet)\n";
					}
				}
			}
			$str_temp =~ s/,$//;
			$str_temp =~ s/e/d/g;
			$str_temp2 =~ s/,$//;
			$str_temp2 =~ s/e/d/g;
			$str_temp3 =~ s/e/d/g;
			if($nmol_types_used==1){
				print OUT "\treal(kind(1.d0)), parameter :: psat = $str_temp\n";
				print OUT "\treal(kind(1.d0)), parameter :: monvol = $str_temp2\n";
			}else{
				print OUT "\treal(kind(1.d0)), parameter :: psat($nmol_types_used) = (/$str_temp/)\n";
				print OUT "\treal(kind(1.d0)), parameter :: monvol($nmol_types_used) = (/$str_temp2/)\n";
			}
			print OUT "\treal(kind(1.d0)), parameter :: sigma = $str_temp3\n\n";

			if($nmol_types_used>1){
				print OUT "\tif (nclust_inc .eq. 0) then\n";
				print OUT "\t\tcall get_molecule_numbers$append_to_eq_names(nclust_inc,indices)\n";
				print OUT "\t\tcall get_cluster_numbers$append_to_eq_names(clust_from_indices)\n";
				print OUT "\t\tcall monomer_indices$append_to_syst_names(n_monomers)\n";
				if($lhs_tests){
					print OUT "\t\tallocate(lhs(nrates))\n\t\tallocate(deltah(nrates))\n\t\tallocate(deltas(nrates))\n";
					print OUT "\t\tdo i = 1,nclust_inc\n";
					@temp_array = ('A','N');
					for($i=0;$i<=$#temp_array;$i++){
						for($imol=1;$imol<=$nmol_types_used;$imol++){
							if($molecule_name[$mol_types_used[$imol]] eq $temp_array[$i]){
								print OUT "\t\t\tind(".($i+1).") = indices(i,$imol)\n";
								last;
							}
						}
					}
					print OUT "\t\t\tcall get_hsdata$append_to_ext_names(ind,lhs(i),deltah(i),deltas(i))\n";
					print OUT "\t\tend do\n";
				}
				print OUT "\tend if\n\n";
			}
			
			print OUT "\tE = 0.d0\n\n";
			
			if($variable_temp){
				print "\nVariable temperature not implemented in the psat and sigma properties.\n\n";
			}else{
				print OUT "\tcall get_coll$append_to_eq_names(nrates,K)\n";
			}
			
			if($nmol_types_used==1){
				if($lloop_cs){
					print OUT "\tdo i = 1,nclust-2\n";
				}else{
					print OUT "\tdo i = 1,nclust-1\n";
				}
				print OUT "\t\tcall get_masses_and_radii$append_to_eq_names(m,r,i+1)\n";
				if($rlim_no_evap !~ /^\s*$/){
					print OUT "\t\tif(r .ge. $rlim_no_evap_str) then\n";
					print OUT "\t\t\texit\n";
					print OUT "\t\tend if\n";
				}
				print OUT "\t\tE(i,1) = K(i,1)*psat/$string1*exp((2.d0*sigma*monvol)/($string1*r))\n";
				print OUT "\t\tif (i .eq. 1) then\n";
				print OUT "\t\t\tE(i,1) = .5d0*E(i,1)\n";
				print OUT "\t\tend if\n";
				print OUT "\tend do\n\n";
			}else{
				# Loop over the evaporation of each component
				print OUT "\tdo imol = 1,$nmol_types_used\n";
				print OUT "\t\ti = n_monomers(imol)\n";
				print OUT "\t\tdo j = 1,$nclust_included\n";
				print OUT "\t\t\tij_ind = indices(i,:)+indices(j,:)\n";
				print OUT "\t\t\tcall get_masses_and_radii$append_to_eq_names(m,r,ij_ind)\n";
				if($rlim_no_evap !~ /^\s*$/){
					print OUT "\t\t\tif(r .ge. $rlim_no_evap_str) then\n";
					print OUT "\t\t\t\tcycle\n";
					print OUT "\t\t\tend if\n";
				}
				print OUT "\t\t\tif (clust_from_indices($nmol_ranges_ij_ind).gt.0";
				if($lloop_cs){
					print OUT " .and. .not.all(ij_ind.eq.ij_ind_cs)";
				}
				print OUT ") then\n";
				$str_temp = "";
				if($lhs_tests){
					print OUT "\t\t\t\tij = clust_from_indices($nmol_ranges_ij_ind)\n";
					print OUT "\t\t\t\tif (lhs(i) .and. lhs(j) .and. lhs(ij)) then\n";
					print OUT "\t\t\t\t\tE(i,j) = K(i,j)*1.01325d5/$string1*&\n\t\t\t\t\t\t\t&exp((deltah(ij)-deltah(i)-deltah(j)-temperature*&\n\t\t\t\t\t\t\t&1.d-3*(deltas(ij)-deltas(i)-deltas(j)))*$string2)\n";
					print OUT "\t\t\t\telse\n";
					$str_temp = "\t";
				}
				print OUT "$str_temp\t\t\t\txmol = real(ij_ind(imol),kind=kind(1.d0))/real(sum(ij_ind),kind=kind(1.d0))\n";
				print OUT "$str_temp\t\t\t\tE(i,j) = K(i,j)*psat(imol)*xmol/$string1*&\n$str_temp\t\t\t\t\t\t&exp((2.d0*sigma*monvol(imol))/($string1*r))\n";
				if($lhs_tests){
					print OUT "\t\t\t\tend if\n";
				}
				print OUT "\t\t\t\tif (i .eq. j) then\n";
				print OUT "\t\t\t\t\tE(i,j) = .5d0*E(i,j)\n";
				# For heterodimers, the Kelvin approximation gives different results depending on which
				# molecule is assumed to be the "particle" -> use the higher value for the evaporation rate
				print OUT "\t\t\t\telse if (E(j,i) .gt. E(i,j)) then\n";
				print OUT "\t\t\t\t\tE(i,j) = E(j,i)\n";
				print OUT "\t\t\t\tend if\n";
				print OUT "\t\t\t\tE(j,i) = E(i,j)\n";
				print OUT "\t\t\tend if\n";
				print OUT "\t\tend do\n";
				print OUT "\tend do\n\n";
			}
			
		}else{
			die "\nCan't understand evaporation coefficient definition $loop_evap_coef.\n\n";
		}
		
	}else{
	
################################################################################
################################################################################
##      11.2 Reading in rates for specific evaporations                       ##
################################################################################
################################################################################

		if($evaporation_coef_file_name ne ''){
            if(!$lsilent){
                print "\nEvaporation rate file: $evaporation_coef_file_name\n";
            }
			open(EVAPORATION, "<$evaporation_coef_file_name") || die "\nCould not open evaporation rate file $evaporation_coef_file_name\n\n";
			chomp(@temp_array=<EVAPORATION>);
			close(EVAPORATION);
			$number_of_lines=$#temp_array;
			$iline2 = 0;
			for($iline=0;$iline<=$number_of_lines;$iline++){
				next if ($temp_array[$iline] =~ /^\#/);
				if($temp_array[$iline] =~ /(\d+$name_water-?\d+)|(\d+$name_water\s*$)/){
					die "$evaporation_coef_file_name: Evaporation rate cannot be given for hydrates for now (if hydrate averaging is used, the given rate for dry clusters is taken to be the effective rate)";
				}
				@columns=split(' ',$temp_array[$iline]);			
				die "\n$columns[0] on line $iline in file $evaporation_coef_file_name should be a number\n\n" if (!&is_pos_number($columns[0]));
				die "\nThere should be two or three columns on line $iline in file $evaporation_coef_file_name: the rate and the evaporating cluster, or the rate and the mother cluster and the evaporator\n\n" if ($#columns < 1 || $#columns > 2);
				$evaporation_coef_in[$iline2][0] = $columns[0];
				push(@{ $evaporation_coef_in[$iline2] },$columns[1]);
				if($#columns>1){
					push(@{ $evaporation_coef_in[$iline2] },$columns[2]);
				}
				$iline2++;
			}
		}

	################################################################################
	################################################################################
	##      11.3 Reading in scaling factors for the evaporation rates             ##
	################################################################################
	################################################################################

		if(($scale_evap_factor[0][0] == 0) && ($scale_evap_file_name eq '')){
			$l_scale_evap = 0;
		}else{
			$l_scale_evap = 1;
			if($scale_evap_file_name ne ''){
                if(!$lsilent){
                    print "\nEvaporation rate scaling file: $scale_evap_file_name\n";
                }
				open(SCALE, "<$scale_evap_file_name") || die "\nCould not open evaporation rate scaling file $scale_evap_file_name\n\n";
				chomp(@temp_array=<SCALE>);
				close(SCALE);
				$number_of_lines=$#temp_array;
				if($scale_evap_factor[0][0] == 0){
					$iline2 = 0;
				}else{
					$iline2 = 1;
				}
				for($iline=0;$iline<=$number_of_lines;$iline++){
					next if ($temp_array[$iline] =~ /^\#/);
					@columns=split(' ',$temp_array[$iline]);
					die "\n$columns[0] on line $iline in file $scale_evap_file_name should be a number\n\n" if (!&is_pos_number($columns[0]));
					$scale_evap_factor[$iline2][0] = $columns[0];
					if($#columns>0){
						push(@{ $scale_evap_factor[$iline2] },$columns[1]);
						if($#columns>1){
							push(@{ $scale_evap_factor[$iline2] },$columns[2]);
						}
					}
					$iline2++;
				}
			}
		}

	################################################################################
	################################################################################
	##      11.4 Calculating the evaporation rates                                ##
	################################################################################
	################################################################################

		# Looping through the possible evaporations
		for($kclus=1;$kclus<=$max_cluster;$kclus++){
			for($i=1;$i<=2*$ind_lin_loss[$kclus][0];$i+=2){
				$jclus = $ind_lin_loss[$kclus][$i];
				$iclus = $ind_lin_loss[$kclus][$i+1];
			
				# Skipping, if this is a loss term
				if($iclus>$max_cluster || $jclus>$max_cluster){
					next;
				}
			
				$iclus_label=$label[$iclus];
				$jclus_label=$label[$jclus];
				$kclus_label=$label[$kclus];
			
	################################################################################
	################################################################################
	##         11.41 Determining if this evaporation has been given               ##
	##               a fixed rate value in the evaporation rate file              ##
	################################################################################
	################################################################################
			
				$levap_coef_in[$iclus][$jclus] = 0;
		
				if($evaporation_coef_file_name ne ''){
					for($iline=0;$iline<=$#evaporation_coef_in;$iline++){
						if(&compare_clusters($kclus_label,$evaporation_coef_in[$iline][1])){
							if(($#{ $evaporation_coef_in[$iline] } == 1) || (&compare_clusters($iclus_label,$evaporation_coef_in[$iline][2]) || &compare_clusters($jclus_label,$evaporation_coef_in[$iline][2]))){
								$levap_coef_in[$iclus][$jclus] = 1;
								$evap_coef[$iclus][$jclus] = $evaporation_coef_in[$iline][0];
								last;
							}
						}
					}
				}
			
				if($levap_coef_in[$iclus][$jclus]){
			
					$evap_coef_eff[$iclus][$jclus] = $evap_coef[$iclus][$jclus];
			
	################################################################################
	################################################################################
	##         11.42 Calculating the free energy -based evaporation rate          ##
	################################################################################
	################################################################################

				}else{
                    
                    if($l_no_delta_g_data[$iclus] || $l_no_delta_g_data[$jclus] || $l_no_delta_g_data[$kclus]){
                        die "Missing free energy or input evaporation rate data for $kclus_label -> $iclus_label + $jclus_label\n";
                    }
			
	################################################################################
	################################################################################
	##            11.421 Figuring out scaling factors for each evaporation        ##
	################################################################################
	################################################################################
			
					if($l_scale_evap == 1){
						$temp_val = 0;
						for($iline=0;$iline<=$#scale_evap_factor;$iline++){
							if($#{ $scale_evap_factor[$iline] } == 0){
								$temp_val = $scale_evap_factor[$iline][0];
							}elsif(&compare_clusters($iclus_label,$scale_evap_factor[$iline][1]) || &compare_clusters($jclus_label,$scale_evap_factor[$iline][1])){
								if(($#{ $scale_evap_factor[$iline] } == 1) || &compare_clusters($kclus_label,$scale_evap_factor[$iline][2])){
									$temp_val = $scale_evap_factor[$iline][0];
								}
							}
						}
						if($temp_val != 0){
							$evap_coef_scale[$iclus][$jclus]=$temp_val*$kcal_per_mol_to_J;
							$evap_coef_scale[$jclus][$iclus]=$evap_coef_scale[$iclus][$jclus];
						}
					}

					if($l_evap_factor_mcmc && (!defined $delta_g[$iclus] || !defined $delta_g[$jclus] || !defined $delta_g[$kclus])){
						$evap_coef[$iclus][$jclus] = -1;
						$missing_energies += 1;
					}elsif(!$variable_temp){
						# calculate the evaporation rates of all possible combinations of hydrates of these dry clusters
						@distr_temp = @{$distr[$iclus]};
						@distr_temp2 = @{$distr[$jclus]};
						@distr_temp3 = @{$distr[$kclus]};
				
						# Effective evaporation rate
						$evap_coef_eff[$iclus][$jclus]=0.0;
				
						for($khydr=0;$khydr<=$#distr_temp3;$khydr++){
							if(!(defined $distr_temp3[$khydr])){
                                next;
                            }
                            $lfound = 0;
							for($ihydr=0;$ihydr<=$#distr_temp;$ihydr++){
								if(!(defined $distr_temp[$ihydr])){
									next;
								}
								$jhydr = $khydr-$ihydr;
								if($jhydr<0 || $jhydr>$#distr_temp2 || !(defined $distr_temp2[$jhydr])){
									next;
								# Don't count the same evaporation twice
								}elsif($iclus==$jclus && $jhydr<$ihydr){
									next;
								}else{
									$lfound = 1;
								}
							
								if($lcoll_coef_in[$iclus][$jclus] && ($ihydr>0 || $jhydr>0)){
									die "Cannot give one collision rate for $iclus_label and $jclus_label if you want to average the evaporation rate over hydrates";
								}
							
								if($ihydr != 0){
									$temp_label=$iclus_label.$ihydr.$name_water;
								}else{
									$temp_label=$iclus_label;
								}
								if($jhydr != 0){
									$temp_label2=$jclus_label.$jhydr.$name_water;
								}else{
									$temp_label2=$jclus_label;
								}
					
								$evap_coef_temp=$delta_g_hydr[$kclus][$khydr]-$delta_g_hydr[$iclus][$ihydr]-$delta_g_hydr[$jclus][$jhydr];

								if(defined $evap_coef_scale[$iclus][$jclus]){
									$evap_coef_temp+=$evap_coef_scale[$iclus][$jclus];
								}

								$evap_coef_temp /= ($boltz*$temperature);
								$evap_coef_temp += log($pressure*1.0/$boltz/$temperature);
								$evap_coef_temp = exp($evap_coef_temp)*$coll_coef_hydr[$iclus][$jclus][$ihydr][$jhydr];
					
								# Divide by two if the evaporators are similar
								if($iclus == $jclus && $ihydr == $jhydr){
									$evap_coef_temp *= 0.5;
								}
								$evap_coef_hydr[$iclus][$jclus][$ihydr][$jhydr] = $evap_coef_temp;
							
	################################################################################
	################################################################################
	##      11.5 Hydrate averaged evaporation rate                                ##
	################################################################################
	################################################################################

						
								# Evaporation rate without ion enhancement, weighted with the hydrate distribution
								$temp_val2 = $distr_temp3[$khydr]*$evap_coef_temp;
								# Ion enhancement for ion-neutral collisions
								if($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus] == 1){
									$temp_val2 *= $fcr_hydr[$iclus][$jclus][$ihydr][$jhydr];
								}
								$evap_coef_eff[$iclus][$jclus] += $temp_val2;
						

							}
							if(!$lfound){
								$string = $iclus_label . "i$name_water + " . $jclus_label . "j$name_water";
								die "No possible evaporation products for $kclus_label$khydr$name_water -> $string.\n";
							}
						}
						if(!$lhydrate_average){
							$evap_coef[$iclus][$jclus] = $evap_coef_hydr[$iclus][$jclus][0][0];
						}else{
							$evap_coef[$iclus][$jclus] = $evap_coef_eff[$iclus][$jclus];
						}
				
	################################################################################
	################################################################################
	##      11.6 Temperature dependent evaporation rate                           ##
	################################################################################
	################################################################################

					# If we are using a variable temperature, we don't have a hydrate distribution.
					}else{
						if($lfortran){
							$string = "&\n\t\t\t &";
						}else{
							$string = " ...\n\t\t\t";
						}
						if($delta_g[$iclus] ne '0'){
							$string1 = "$string-$delta_g[$iclus]";
						}else{
							$string1 = '';
						}
						if($delta_g[$jclus] ne '0'){
							$string2 = "$string-$delta_g[$jclus]";
						}else{
							$string2 = '';
						}
						$evap_coef[$iclus][$jclus]="$delta_g[$kclus]$string1$string2";
						if(defined $evap_coef_scale[$iclus][$jclus]){
							$str_temp = sprintf('%.14e',$evap_coef_scale[$iclus][$jclus]/$kcal_per_mol_to_J);
							if($lfortran){
								$str_temp =~ s/e/d/;
							}
							$evap_coef[$iclus][$jclus]="$evap_coef[$iclus][$jclus]$string+$str_temp/temperature";
						}
						$temp_val = $kcal_per_mol_to_J/$boltz;
						$str_temp = sprintf('%.14e',$temp_val);
						if($lfortran){
							$str_temp =~ s/e/d/;
						}
						$evap_coef[$iclus][$jclus] = "exp($string($evap_coef[$iclus][$jclus])$string*$str_temp)";
						$temp_val = $pressure/$boltz;
						$str_temp = sprintf('%.14e',$temp_val);
						if($lfortran){
							$str_temp =~ s/e/d/;
						}
						$evap_coef[$iclus][$jclus] = "$str_temp/temperature*$evap_coef[$iclus][$jclus]*K($iclus,$jclus)";
	
						#### Divide by two if the evaporators are similar, since we want to have the evaporation coefficient from the point of view of the evaporator
						if($iclus == $jclus){
							if($lfortran){
								$evap_coef[$iclus][$jclus] = "0.5d0*$evap_coef[$iclus][$jclus]";
							}else{
								$evap_coef[$iclus][$jclus] = "0.5*$evap_coef[$iclus][$jclus]";
							}
						}else{
							$evap_coef[$jclus][$iclus] = $evap_coef[$iclus][$jclus];
						}
					}
				
				}	
			
	################################################################################
	################################################################################
	##      11.7 Printing out the evaporation rates                               ##
	################################################################################
	################################################################################

				# Make the 0.5 factor visible for clarity, if products are similar (already done for variable_temp)
			
				$value_string = "";
				$evap_string = "$kclus_label -> $iclus_label + $jclus_label";
				$fixed_string = "";
				$fcr_string = "";
				$hydr_string = "";
			
				if($levap_coef_in[$iclus][$jclus]){
			
					$fixed_string = ", evaporation rate given as input";
					$value_string = sprintf('%.14e',$evap_coef[$iclus][$jclus]);
					if($lfortran){
						$value_string =~ s/e/d/;
					}
			
				}else{
			
					if($lcoll_coef_in[$iclus][$jclus]){
						$fixed_string = ", collision rate given as input";
					}
			
					# When using hydrates, print also the dry value (FCR & collision coefficient) for comparison.
					if($lhydrate_average){
						if($lhas_hydr[$kclus]){
							if(defined $evap_coef_hydr[$iclus][$jclus][0][0]){
                                if($iclus == $jclus){
                                    $hydr_string = ", dry value: 0.5*" . sprintf('%.14e',2*$evap_coef_hydr[$iclus][$jclus][0][0]);
                                }else{
                                    if($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus] == 1){
                                        $hydr_string = ", dry value: " . sprintf('%.14e',$fcr_hydr[$iclus][$jclus][0][0]*$evap_coef_hydr[$iclus][$jclus][0][0]) . ", including ion enhancement " . sprintf('%.3g',$fcr_hydr[$iclus][$jclus][0][0]) . "*" . sprintf('%.2e',$evap_coef_hydr[$iclus][$jclus][0][0]);
                                    }else{
                                        $hydr_string = ", dry value: " . sprintf('%.14e',$evap_coef_hydr[$iclus][$jclus][0][0]);
                                    }
                                }
                            }else{
                                $hydr_string = ", dry value undefined";
                            }
							if($sticking_coef[$iclus][$jclus] ne ''){
								$hydr_string = "$hydr_string (sticking coef.  $sticking_coef[$iclus][$jclus])";
							}
						}else{
							$hydr_string = ", no hydrates";
						}
						if($iclus == $jclus){
							$value_string = sprintf('%.14e',2*$evap_coef_eff[$iclus][$jclus]);
							if($lfortran){
								$value_string =~ s/e/d/;
								$value_string = ".5d0*$value_string";
							}else{
								$value_string = ".5*$value_string";
							}
						}else{
							$value_string = sprintf('%.14e',$evap_coef_eff[$iclus][$jclus]);
							if($lfortran){
								$value_string =~ s/e/d/;
							}
						}
					}else{					
						if($variable_temp){
							$value_string = $evap_coef[$iclus][$jclus];
							if($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus] == 1){
								$fcr_string = ", including ion enhancement" if(!$lcoll_coef_in[$iclus][$jclus]);
							}					
						}elsif($iclus == $jclus){
							$value_string = sprintf('%.14e',2*$evap_coef[$iclus][$jclus]);
							if($lfortran){
								$value_string =~ s/e/d/;
								$value_string = "0.5d0*$value_string";
							}else{
								$value_string = "0.5*$value_string";
							}
						}else{
							if($lneutral_cluster[$iclus]+$lneutral_cluster[$jclus] == 1){
								$value_string = sprintf('%.14e',$fcr[$iclus][$jclus]*$evap_coef[$iclus][$jclus]);
								if(!$lcoll_coef_in[$iclus][$jclus]){
									$fcr_string = ", including ion enhancement " . sprintf('%.3g',$fcr[$iclus][$jclus]) . "*" . sprintf('%.2e',$evap_coef[$iclus][$jclus]);
								}
							}else{
								$value_string = sprintf('%.14e',$evap_coef[$iclus][$jclus]);
							}
						
							if($lfortran){
								$value_string =~ s/e/d/;
							}
						
						}
					
					}
				
					# Add a possible sticking coefficient
					$value_string = "$sticking_coef[$iclus][$jclus]$value_string" if(!$lcoll_coef_in[$iclus][$jclus]);
			
				}
			
				if($lfortran){
					$string = "$value_string\t! $evap_string$fixed_string$fcr_string$hydr_string";
					if($l_evap_factor_mcmc == 1){
						$icoef_evap += 1;
						# If this is an MCMC coefficient, save the true value to be printed later ...
						if($evap_coef[$iclus][$jclus]<0){
							$coef_true[$ncoef_coll+$icoef_evap] = "-1.d0";
						}else{
							$coef_true[$ncoef_coll+$icoef_evap] = $string;
						}
						# ... and print here just the MCMC coefficient
						print OUT "\tE($iclus,$jclus) = coef(" . ($ncoef_coll+$icoef_evap) . ")\t! $evap_string\n";
					}else{
						print OUT "\tE($iclus,$jclus) = $string\n";
					}
					print OUT "\tE($jclus,$iclus) = E($iclus,$jclus)\n" if($iclus != $jclus);
				}else{
					print EVAP "E($iclus,$jclus) = $value_string;\t% $evap_string$fixed_string$fcr_string$hydr_string\n";
					print EVAP "E($jclus,$iclus) = E($iclus,$jclus);\n" if($iclus != $jclus);
				}
			}
		}
	}
	if($lfortran){
		print OUT "\nend subroutine get_evap$append_to_eq_names\n";
	}
}else{
	if(!$lfortran){
		print EVAP "% Evaporation disabled\n\nE = [];\n";
	}
}

if(!$lfortran){
	if($variable_temp){
		print EVAP "\nend";
	}
	close(EVAP);
}

################################################################################
################################################################################
##   12. Printing the ion loss enhancement factors for Fortran                ##
################################################################################
################################################################################

# In the Matlab version, these are in the get_cs and get_wl files

if($include_ion_terms && $lfortran && ($parameters_in_get_fcr_1 ne '')){
	print OUT "\n!-----------------------------------------------------------\n\n";
	print OUT "subroutine get_fcr$append_to_eq_names($parameters_in_get_fcr_1)\n\timplicit none\n";
	print OUT "\treal(kind(1.d0)) :: $parameters_in_get_fcr_3\n\n";
	print OUT "\t! enhancement factors for ion losses\n\n";
	
	if(!$disable_coag_sinks){
		if($fcs =~ m/\./){
			print OUT "\tfcs = $fcs"."d0\n";
		}else{
			print OUT "\tfcs = $fcs.d0\n";
		}
	}
	if(!$disable_wall_terms || ($l_mcmc_any && $ncoef_wl>0)){
		if($fwl =~ m/\./){
			print OUT "\tfwl = $fwl"."d0\n";
		}else{
			print OUT "\tfwl = $fwl.d0\n";
		}
	}	
	print OUT "\nend subroutine get_fcr$append_to_eq_names\n";
}

################################################################################
################################################################################
##   13. "True" coefficient values for MCMC                                   ##
################################################################################
################################################################################
	
if($lfortran && ($l_coll_factor_mcmc_n_i || $l_coll_factor_mcmc_n_g || ($l_evap_factor_mcmc && $missing_energies<$ncoef_evap))){
	print OUT "\n!-----------------------------------------------------------\n\n";
	print OUT "subroutine coefs_from_data$append_to_eq_names(coef)";
	print OUT "\n\timplicit none\n\treal(kind(1.d0)) :: coef(" . ($n_mcmc_coefs+$variable_cs+2*$variable_ion_source) . ")";
	if($variable_cs || $variable_ion_source){
		print OUT "\n\n\tcoef(1:" . ($n_mcmc_coefs) . ") = 1.d0\n";
	}else{
		print OUT "\n\n\tcoef = 0.d0\n";
	}
	if($l_coll_factor_mcmc_any){
		print OUT "\n\t! " . '"true"' . " values of the collision coefficients (based on hard spheres and possibly ion enhancement)\n";
		if($missing_fcr>0){
			print OUT "\n\t! (-1 for coefficients for which dipole data are missing)\n";
		}
	}
	for($i=1;$i<=$ncoef_coll;$i++){
		if($coef_true[$i] ne ''){
			print OUT "\tcoef($i) = $coef_true[$i]\n";
		}
	}
	if($l_evap_factor_mcmc){
		print OUT "\n\t! " . '"true"' . " values of the evaporation coefficients (based on input energies)\n";
		if($missing_energies+$missing_fcr>0){
			print OUT "\n\t! (-1 for coefficients for which energies or dipole data are missing)\n";
		}
	}
	for($i=$ncoef_coll+1;$i<=$ncoef_coll+$ncoef_evap;$i++){
		if($coef_true[$i] ne ''){
			print OUT "\tcoef($i) = $coef_true[$i]\n";
		}
	}
	if($l_q_neg_mcmc){
		print OUT "\n\tcoef(" . ($ncoef_coll+$ncoef_evap+1) . ") = 3.d6\t\t\t\t\t! typical GCR ion production rate in m^-3s^-1";
	}
	if($l_q_pos_mcmc){
		print OUT "\n\tcoef(" . ($ncoef_coll+$ncoef_evap+$l_q_neg_mcmc+1) . ") = 3.d6\t\t\t\t\t! typical GCR ion production rate in m^-3s^-1";
	}
	if($l_wl_mcmc && $ncoef_wl==1){
		print OUT "\n\tcoef($n_mcmc_coefs) = $cs_value\t\t\t\t! example external loss (Hyytiälä coagulation sink)";
	}elsif($l_mcmc_any && $ncoef_wl>0){
		for($i=$n_mcmc_coefs-$ncoef_wl+1;$i<=$n_mcmc_coefs;$i++){
			if($coef_true[$i] ne ''){
				print OUT "\n\tcoef($i) = $coef_true[$i]";
			}else{
				print OUT "\n\tcoef($i) = $cs_value\t\t\t\t! example external loss (Hyytiälä coagulation sink)";
			}
		}
	}
	print OUT "\n\nend subroutine coefs_from_data$append_to_eq_names";
}

################################################################################
################################################################################
##   14. Finishing the Matlab driver file                                     ##
################################################################################
################################################################################

if(!$lfortran){
	
	print DRIVER "\n\n% Initializing concentrations etc.\n\n";
	print DRIVER "\tC0 = zeros(1,$max_n_flux);\n\n\tisconst = zeros($max_cluster_number,1);\n\tisfitted = zeros($max_cluster_number,1);\n\tC_fit = cell($max_cluster_number,2);\n\tsource = zeros($max_cluster_number,1);\n\n";
	print DRIVER "\tJ_out = nan;\n";
	print DRIVER "\tflux = nan;\n";
	print DRIVER "\toutflux_matrix = nan;\n";
	print DRIVER "\tout = nan;\n";
	print DRIVER "\tsources = nan;\n";
    print DRIVER "\tc_min_th = 1e-6; % Threshold for abs. conc. considered for comparisons/negative values (m^-3)\n\n";

	print DRIVER "% Checking what input we have and processing it\n\n";
	print DRIVER "\tif size(Tmax,1)>size(Tmax,2), Tmax = Tmax'; end\n";
	if(!$l_increase_time){
		print DRIVER "\tfixed_time = 1;\n";
	}else{
		print DRIVER "\tfixed_time = 0;\n";
	}
	if(!$l_old_output){
		print DRIVER "\tif nargout<=7\n";
		print DRIVER "\t\tno_fluxes = 1;\n";
		print DRIVER "\t\tno_j = 1;\n";
		print DRIVER "\t\tcalc_sources = 0;\n";
		print DRIVER "\telseif nargout<=8\n";
		print DRIVER "\t\tno_fluxes = 1;\n";
		print DRIVER "\t\tno_j = 0;\n";
		print DRIVER "\t\tcalc_sources = 0;\n";
		print DRIVER "\telse\n";
		print DRIVER "\t\tno_fluxes = 0;\n";
		print DRIVER "\t\tno_j = 0;\n";
		print DRIVER "\t\tcalc_sources = 1;\n";
		print DRIVER "\tend\n";
	}else{
		print DRIVER "\tno_fluxes = 0;\n\tno_j = 0;\n";
	}
	print DRIVER "\tsources_in = 0;\n\tsources_out = 0;\n\tconsts_out = 0;\n\topt_str = '';\n\tdifftol = 1e-5;\n\tc_neutr = 0;\n\tc_neg = 0;\n\tc_pos = 0;\n\tfl_out = 0;\n\toutmat = 0;\n\tcluster_data = 0;\n\tC_fun_str = {};\n\tn_fun = [];\n";
	
	$line = "\tC0_in = 0;\n\tCSfactor = 1;\n\tWLfactor = 1;\n";
	if($variable_temp){
		$line = $line . "\ttemperature = $temperature;\n";
	}
	$line = $line . "\tif ~isempty(varargin)\n";
	$line = $line . "\t\ti = 0;\n";
	$line = $line . "\t\tif isnumeric(varargin{1})\t% Initial concentrations cm^3 -> m^3\n";
	$line = $line . "\t\t\tC00 = varargin{1}*1e6;\n";
	$line = $line . "\t\t\tC0_in = 1;\n";
	$line = $line . "\t\t\ti = 1;\n";
	$line = $line . "\t\t\tif size(C00,2)==$size_C_out\n";
	if(! $l_save_outgoing){
		$line = $line . "\t\t\t\tC00 = [C00 zeros(size(C00,1)," . ($max_n_flux-$size_C_out) . ")];\n";
	}
	$line = $line . "\t\t\t\tC0 = C00(end,:);\n";
	$line = $line . "\t\t\t\tif (length(varargin)>1 && isnumeric(varargin{2}))\t% Time (vector) corresponding to C00\n";
	$line = $line . "\t\t\t\t\tT00 = varargin{2};\n";
	$line = $line . "\t\t\t\t\tif (isvector(T00) && numel(T00)==size(C00,1))\n";
	$line = $line . "\t\t\t\t\t\ti = 2;\n";
	$line = $line . "\t\t\t\t\t\tif size(T00,2)>size(T00,1), T00 = T00'; end\n";
	$line = $line . "\t\t\t\t\t\tif numel(Tmax)==1\n";
	$line = $line . "\t\t\t\t\t\t\tTmax = Tmax+T00(end);\n";
	$line = $line . "\t\t\t\t\t\tend;\n";
	$line = $line . "\t\t\t\t\telse\n";
	$line = $line . "\t\t\t\t\t\terror('Sizes of initial concentration array and corresponding time array don''t match.')\n";
	$line = $line . "\t\t\t\t\tend\n";
	$line = $line . "\t\t\t\telse\n";
	$line = $line . "\t\t\t\t\tT00 = 0;\n";
	$line = $line . "\t\t\t\tend\n";
	$line = $line . "\t\t\telse\n";
	$line = $line . "\t\t\t\terror('Bad initial concentrations.')\n";
	$line = $line . "\t\t\tend\n";
	$line = $line . "\t\telse\n";
	$line = $line . "\t\t\tT00 = 0;\n";
	$line = $line . "\t\t\tC00 = C0;\n";
	$line = $line . "\t\tend\n";
	print DRIVER $line;
	$line = "\t\t% Check for single keywords in the input arguments\n";
	$line = $line . "\t\tif ismember(1,strcmpi('fixed_time',varargin))\n";
	$line = $line . "\t\t\tfixed_time = 1;\n";
	$line = $line . "\t\t\tvarargin = varargin(~strcmpi('fixed_time',varargin));\n";
	$line = $line . "\t\telseif ismember(1,strcmpi('repeat',varargin))\n";
	$line = $line . "\t\t\tfixed_time = 0;\n";
	$line = $line . "\t\t\tvarargin = varargin(~strcmpi('repeat',varargin));\n";
	$line = $line . "\t\telseif ismember(1,strcmpi('no_dofluxes',varargin))\n";
	$line = $line . "\t\t\tno_fluxes = 1;\n";
	$line = $line . "\t\t\tvarargin = varargin(~strcmpi('no_dofluxes',varargin));\n";
	$line = $line . "\t\telseif ismember(1,strcmpi('no_fluxes',varargin))\n";
	$line = $line . "\t\t\tno_fluxes = 1;\n";
	$line = $line . "\t\t\tno_j = 1;\n";
	$line = $line . "\t\t\tvarargin = varargin(~strcmpi('no_fluxes',varargin));\n";
	$line = $line . "\t\tend\n";
	$line = $line . "\t\t% Go through the paired input arguments\n";
	$line = $line . "\t\tfor j = i+1:2:length(varargin)\n";
	$line = $line . "\t\t\tif strcmpi(varargin{j},'Sources_in')\n";
	$line = $line . "\t\t\t\tsources_in = 1;\n";
	$line = $line . "\t\t\t\tfname1 = varargin{j+1};\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'Sources_out')\n";
	$line = $line . "\t\t\t\tsources_out = 1;\n";
	$line = $line . "\t\t\t\tfname2 = varargin{j+1};\n";
	$line = $line . "\t\t\t\tno_fluxes = 0;\n";
	$line = $line . "\t\t\t\tcalc_sources = 1;\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'Constants_out')\n";
	$line = $line . "\t\t\t\tconsts_out = 1;\n";
	$line = $line . "\t\t\t\tfname2c = varargin{j+1};\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'Options')\n";
	$line = $line . "\t\t\t\topt_str = varargin{j+1};\n";
    $line = $line . "\t\t\telseif strcmpi(varargin{j},'difftol')\n";
	$line = $line . "\t\t\t\tdifftol = varargin{j+1};\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'C_neutr')\n";
	$line = $line . "\t\t\t\tc_neutr = 1;\n";
	$line = $line . "\t\t\t\tfname3 = varargin{j+1};\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'C_neg')\n";
	$line = $line . "\t\t\t\tc_neg = 1;\n";
	$line = $line . "\t\t\t\tfname4 = varargin{j+1};\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'C_pos')\n";
	$line = $line . "\t\t\t\tc_pos = 1;\n";
	$line = $line . "\t\t\t\tfname5 = varargin{j+1};\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'Fluxes')\n";
	$line = $line . "\t\t\t\tfl_out = 1;\n";
	$line = $line . "\t\t\t\tfname6 = varargin{j+1};\n";
	$line = $line . "\t\t\t\tno_fluxes = 0;\n";
	$line = $line . "\t\t\t\tcalc_sources = 1;\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'CSfactor')\n";
	$line = $line . "\t\t\t\tCSfactor = varargin{j+1};\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'WLfactor')\n";
	$line = $line . "\t\t\t\tWLfactor = varargin{j+1};\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'Outmat')\n";
	$line = $line . "\t\t\t\toutmat = 1;\n";
	$line = $line . "\t\t\t\tfname7 = varargin{j+1};\n";
	$line = $line . "\t\t\t\tno_fluxes = 0;\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'Cluster_data')\n";
	$line = $line . "\t\t\t\tcluster_data = 1;\n";
	$line = $line . "\t\t\t\tfname8 = varargin{j+1};\n";
	$line = $line . "\t\t\t\tno_fluxes = 0;\n";
	$line = $line . "\t\t\t\tcalc_sources = 1;\n";
	$line = $line . "\t\t\telseif strcmpi(varargin{j},'Cfun')\n";
	$line = $line . "\t\t\t\tn_fun = [n_fun find(strcmp(clust,varargin{j+1}{1}))];\n";
	$line = $line . "\t\t\t\tisconst(n_fun(end)) = 1;\n";
	$line = $line . "\t\t\t\tif length(varargin{j+1})<2 || isempty(varargin{j+1}{2})\n";
	$line = $line . "\t\t\t\t\terror(['The function related to cluster ',varargin{j+1}{1},' was not given.'])\n";
	$line = $line . "\t\t\t\tend\n";
	$line = $line . "\t\t\t\tC_fun_str{n_fun(end)} = ['1e6*', varargin{j+1}{2},'('];\n";
	$line = $line . "\t\t\t\tC_fun_str_2{n_fun(end)} = ['1e6*', varargin{j+1}{2},'('];\n";
	$line = $line . "\t\t\t\tC_fun_str_3{n_fun(end)} = ['1e6*', varargin{j+1}{2},'('];\n";
	$line = $line . "\t\t\t\tfor k = 3:length(varargin{j+1})\n";
	$line = $line . "\t\t\t\t\tif strcmpi(varargin{j+1}{k},'t')\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str{n_fun(end)} = [C_fun_str{n_fun(end)}, 't'];\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str_2{n_fun(end)} = [C_fun_str_2{n_fun(end)}, 'T(j)'];\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str_3{n_fun(end)} = [C_fun_str_3{n_fun(end)}, 'T'];\n";
	$line = $line . "\t\t\t\t\telse\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str{n_fun(end)} = [C_fun_str{n_fun(end)}, '1e-6*c(', num2str(find(strcmp(clust,varargin{j+1}{k}))), ')'];\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str_2{n_fun(end)} = [C_fun_str_2{n_fun(end)}, '1e-6*C(j,', num2str(find(strcmp(clust,varargin{j+1}{k}))), ')'];\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str_3{n_fun(end)} = [C_fun_str_3{n_fun(end)}, '1e-6*C(j,', num2str(find(strcmp(clust,varargin{j+1}{k}))), ')'];\n";
	$line = $line . "\t\t\t\t\tend\n";
	$line = $line . "\t\t\t\t\tif k<length(varargin{j+1})\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str{n_fun(end)} = [C_fun_str{n_fun(end)}, ','];\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str_2{n_fun(end)} = [C_fun_str_2{n_fun(end)}, ','];\n";
	$line = $line . "\t\t\t\t\t\tC_fun_str_3{n_fun(end)} = [C_fun_str_3{n_fun(end)}, ','];\n";
	$line = $line . "\t\t\t\t\tend\n\t\t\t\tend\n";
	$line = $line . "\t\t\t\tC_fun_str{n_fun(end)} = [C_fun_str{n_fun(end)}, ')'];\n";
	$line = $line . "\t\t\t\tC_fun_str_2{n_fun(end)} = [C_fun_str_2{n_fun(end)}, ')'];\n";
	$line = $line . "\t\t\t\tC_fun_str_3{n_fun(end)} = [C_fun_str_3{n_fun(end)}, ')'];\n";
	if($variable_temp){
		$line = $line . "\t\t\telseif strcmpi(varargin{j},'Temperature')\n";
		$line = $line . "\t\t\t\ttemperature = varargin{j+1};\n";
	}

	$line = $line . "\t\t\tend\n";
	$line = $line . "\t\tend\n";
	$line = $line . "\tend\n";
	print DRIVER $line;

	print DRIVER "\tif ~isempty(n_fun)\n";
	print DRIVER "\t\tn_fun = sort(n_fun);\n";
	print DRIVER "\t\tdC_fun_str = 'dcdt = \@($input_for_eq) $output_function_name(t,[c(1:';\n";
	print DRIVER "\t\tfor i = 1:length(n_fun)\n";
	print DRIVER "\t\t\tdC_fun_str = [dC_fun_str, num2str(n_fun(i)-1),');',C_fun_str{n_fun(i)}, ';c(', num2str(n_fun(i)+1), ':'];\n";
	print DRIVER "\t\tend\n";
	print DRIVER "\t\tdC_fun_str = [dC_fun_str, 'end)],$input_for_eq_C_fun);'];\n";
	print DRIVER "\t\teval(dC_fun_str);\n";
	print DRIVER "\telse\n";
	print DRIVER "\t\tdcdt = \@($input_for_eq) $output_function_name($input_for_eq);\n";
	print DRIVER "\tend\n\n";
	
	print DRIVER "\tif numel(Tmax)>1\n";
	print DRIVER "\t\tif Tmax(1)==T00(end)\n";
	print DRIVER "\t\t\tTmax = Tmax(2:end);\n";
	print DRIVER "\t\tend\n";
	print DRIVER "\tend\n\n";
	
	print DRIVER "\tif cluster_data\n";
	print DRIVER "\t\tsave(fname8, 'clust', 'diameters', 'mobility_diameters', 'masses', 'monomers', 'nonmonomers', 'neutrals', 'negatives', 'positives', 'clust_flux','" . $molecule_name[0] . "_in_clust')\n";
	print DRIVER "\tend\n";
	
	print DRIVER "\n% If input source file was given, reading its content and converting cm^3 -> m^3\n\tif sources_in";
	print DRIVER "\n\n\t\tsfid = fopen(fname1, 'r');\n";
	print DRIVER "\t\tif sfid == -1\n\t\terror('Source file not found!')\n\t\tend\n";
	print DRIVER "\t\tA = textscan(sfid, '\%s \%s \%f \%s', 'commentStyle', '\%');\n\t\tfclose(sfid);\n";
	print DRIVER "\t\tA2 = A{2}(cellfun('isempty',regexp(A{1},'^(wall|coag)')));\n";
	print DRIVER "\t\tif any(~ismember(A2,clust)), warning(['Discarding erroneous cluster names in ',fname1]), end\n\n";

	print DRIVER "\t\tfor i=1:$max_cluster_number\n";
	print DRIVER "\t\t\tj = find(strcmp(A{2},clust{i}));\n";
	print DRIVER "\t\t\tdefined = 0;\n";
	print DRIVER "\t\t\tfor k=1:length(j)\n";
	print DRIVER "\t\t\t\tif (~C0_in && strncmp(A{1}(j(k)),'i',1))\n";
	print DRIVER "\t\t\t\t\tif (defined == 1 || defined == 3), error('Source term multiply defined.'), end\n";
	print DRIVER "\t\t\t\t\tC0(i) = A{3}(j(k))*1e6;\n";
	print DRIVER "\t\t\t\t\tdefined = 1;\n";
	print DRIVER "\t\t\t\telseif strncmp(A{1}(j(k)),'s',1)\n";
	print DRIVER "\t\t\t\t\tif (defined > 1), error('Source term multiply defined.'), end\n";
	print DRIVER "\t\t\t\t\tsource(i) = A{3}(j(k))*1e6;\n";
	print DRIVER "\t\t\t\t\tdefined = 2;\n";
	print DRIVER "\t\t\t\telseif strncmp(A{1}(j(k)),'c',1)\n";
	print DRIVER "\t\t\t\t\tif (defined > 0), error('Source term multiply defined.'), end\n";
	print DRIVER "\t\t\t\t\tif length(A{4})<j(k) || isempty(A{4}{j(k)})\n";
	print DRIVER "\t\t\t\t\t\tisconst(i) = 1;\n";
	print DRIVER "\t\t\t\t\t\tC0(i) = A{3}(j(k))*1e6;\n";
	print DRIVER "\t\t\t\t\telse\n";
	print DRIVER "\t\t\t\t\t\tC_fit{i,1} = A{3}(j(k))*1e6;\n";
	print DRIVER "\t\t\t\t\t\tC_fit{i,2} = [];\n";
	print DRIVER "\t\t\t\t\t\tA4 = regexp(A{4}{j(k)},'-','split');\n\t\t\t\t\t\tA4(cellfun('isempty',A4)) = [];\n";
    print DRIVER "\t\t\t\t\t\tif any(~ismember(A4,clust)), warning(['Discarding erroneous cluster names in ',fname1]), end\n";
	print DRIVER "\t\t\t\t\t\tfor i2=1:$max_cluster_number\n";
	print DRIVER "\t\t\t\t\t\t\tfor l=1:length(find(strcmp(A4,clust{i2})))\n";
	print DRIVER "\t\t\t\t\t\t\t\tC_fit{i,2} = [C_fit{i,2},i2];\n";
	print DRIVER "\t\t\t\t\t\t\tend\n";
	print DRIVER "\t\t\t\t\t\tend\n";
	print DRIVER "\t\t\t\t\t\tif ~isempty(C_fit{i,2})\n";
	print DRIVER "\t\t\t\t\t\t\tisfitted(i) = 1;\n";
	print DRIVER "\t\t\t\t\t\telse\n";
	print DRIVER "\t\t\t\t\t\t\tisconst(i) = 1;\n";
	print DRIVER "\t\t\t\t\t\tend\n";
	print DRIVER "\t\t\t\t\t\tC0(i) = A{3}(j(k))*1e6-sum(C0(C_fit{i,2}));\n";
	print DRIVER "\t\t\t\t\tend\n";
	print DRIVER "\t\t\t\t\tdefined = 3;\n";
	print DRIVER "\t\t\t\tend\n\t\t\tend\n\t\tend\n\n";
	print DRIVER "\t\tC00(end,:) = C0;\n";
	print DRIVER "\t\tj = find(strncmp(A{1},'wall',4));\n";
	print DRIVER "\t\tif length(j) > 1\n\t\t\terror('Wall loss enhancement multiply defined.')\n\t\tend\n";
	print DRIVER "\t\tif ~isempty(j),\n";
	print DRIVER "\t\t\tfwl_in = A{3}(j);\n";
	print DRIVER "\t\tend\n";
	print DRIVER "\t\tj = find(strncmp(A{1},'coag',4));\n";
	print DRIVER "\t\tif length(j) > 1\n\t\t\terror('Coagulation loss enhancement multiply defined.')\n\t\tend\n";
	print DRIVER "\t\tif ~isempty(j),\n";
	print DRIVER "\t\t\tfcs_in = A{3}(j);\n";
	print DRIVER "\t\tend\n";
	print DRIVER "\telseif C0_in == 0\n\t\terror('Input concentrations or source terms must be given either in the vector C0 or the file ''Sources_in''!');\n\tend\n\n";
	
	print DRIVER "% Setting the options for the solver\n";
	print DRIVER "\teval(['options = odeset(',opt_str,');']);\n\n";
	
	if(!$variable_temp){
		if($l_reac_in_clus){
			print DRIVER "% Reading in the reaction, collision and evaporation rates, coagulation losses and wall losses (enhancement factors for ion losses included in the loss rate files)\n";
			print DRIVER "\tget_reac$append_to_file_names;\n";
		}else{
			print DRIVER "% Reading in the collision and evaporation rates, coagulation losses and wall losses (enhancement factors for ion losses included in the loss rate files)\n";
		}
		print DRIVER "\tget_coll$append_to_file_names;\n\tget_evap$append_to_file_names;\n\tget_cs$append_to_file_names;\n\tget_wl$append_to_file_names;\n";
	}else{
		if($l_reac_in_clus){
			print DRIVER "% Reading in the reaction, collision and evaporation rates, coagulation losses and wall losses (enhancement factors for ion losses included in the loss rate files)\n";
			print DRIVER "\tR = get_reac$append_to_file_names(temperature);\n";
		}else{
			print DRIVER "% Reading in the collision and evaporation rates, coagulation losses and wall losses (enhancement factors for ion losses included in the loss rate files)\n";
		}
		print DRIVER "\tK = get_coll$append_to_file_names(temperature);\n\tE = get_evap$append_to_file_names(temperature,K);\n\tget_cs$append_to_file_names;\n\tget_wl$append_to_file_names;\n";
	}
	
	print DRIVER "\n\tCS = CS*CSfactor;\n\tWL = WL*WLfactor;\n";
	
	if($include_ion_terms){
		print DRIVER "\tif exist('fcs_in','var')\n\t\tfcs = fcs_in;\n\tend\n";
		print DRIVER "\tif exist('fwl_in','var')\n\t\tfwl = fwl_in;\n\tend\n";
	}
	
	print DRIVER "\n% Solving the birth-death equations\n";

	print DRIVER "\tconverged = 0;\n";
	print DRIVER "\ti = 0;\n";
	print DRIVER "\tTfin = Tmax;\n";
	print DRIVER "\tif fixed_time\n";
	print DRIVER "\t\timax = 1;\n";
	print DRIVER "\telse\n";
	print DRIVER "\t\timax = 5;\n";
	print DRIVER "\t\tTadd = Tmax-T00(end);\n";
	print DRIVER "\tend\n";
	print DRIVER "\twhile ~converged\n";
	print DRIVER "\t\ti = i+1;\n";
	print DRIVER "% Checking for negative concentrations\n";
	print DRIVER "\t\tif min(min(C00)) < -c_min_th\n";
	print DRIVER "\t\t\tconverged = -1;\n";
	print DRIVER "\t\t\tCf = nan(size(C0));\n";
	print DRIVER "\t\t\tC = C00*1e-6;\n";
	print DRIVER "\t\t\tT = T00;\n";
	print DRIVER "\t\t\tJ_out = nan;\n";
	print DRIVER "\t\t\tflux = nan;\n";
	print DRIVER "\t\t\toutflux_matrix = nan;\n";
	print DRIVER "\t\t\tout = nan;\n";
	print DRIVER "\t\t\tsources = nan;\n";
#	print DRIVER "\t\t\tform = nan;\n";
	print DRIVER "\t\t\treturn;\n";
	print DRIVER "\t\tend\n";
	print DRIVER "\t\tif i>imax\n";
	print DRIVER "% Not converged but exiting anyway\n";
	if($l_old_output){
		print DRIVER "\t\t\tif nargout < 11\n";
	}else{
		print DRIVER "\t\t\tif nargout < 3\n";
	}
	print DRIVER "\t\t\t\tdisp('Not converging, try a larger Tmax');\n";
	print DRIVER "\t\t\tend\n";
	print DRIVER "\t\t\tbreak;\n";
	print DRIVER "\t\telseif i>1\n";
	print DRIVER "% Adding more time in order to reach convergence\n";
    print DRIVER "\t\t\tTfin = T00(end)+Tadd;\n";
	print DRIVER "\t\tend\n";	
	print DRIVER "\t\t[T,C] = ode15s(@(t,c) dcdt($input_for_eq), [T00(end) Tfin], C0, options);\n";
	print DRIVER "\t\tif i == 1 && min(min(C)) < 0;\n";
	print DRIVER "\t\t\t[T5,C5] = ode15s(@(t,c) dcdt($input_for_eq), [T00(end) T00(end)+(Tfin(1)-T00(end))*1e-6], C0, options);\n";
	print DRIVER "\t\t\t[T,C] = ode15s(@(t,c) dcdt($input_for_eq), [T5(end) Tfin], C5(end,:), options);\n";
	print DRIVER "\t\t\tif numel(Tmax)==1\n";
	print DRIVER "\t\t\t\tT = [T5; T(2:end)];\n";	
	print DRIVER "\t\t\t\tC = [C5; C(2:end,:)];\n";
	print DRIVER "\t\t\tend\n";
	print DRIVER "\t\tend\n";
	print DRIVER "\t\tCf = C(end,:);\n";
	print DRIVER "\t\tif max(abs(Cf(1:$max_cluster_number)-C0(1:$max_cluster_number))./max(C0(1:$max_cluster_number),c_min_th)) < difftol\n\t\t\tconverged = 1;\n";
	print DRIVER "\t\telseif length(T)>2 && max(abs(Cf(1:$max_cluster_number)-C(floor(length(T)*.75),1:$max_cluster_number))./max(C(floor(length(T)*.75),1:$max_cluster_number),c_min_th)) < difftol\n\t\t\tconverged = 1;\n\t\tend\n";
	print DRIVER "\t\tif any(isfitted)\n";
	print DRIVER "\t\t\tfor j = 1:$max_cluster_number\n";
	print DRIVER "\t\t\t\tif isfitted(j)\n";
	print DRIVER "\t\t\t\t\tif abs(C_fit{j,1}-Cf(j)-sum(Cf(C_fit{j,2})))/C_fit{j,1} > difftol\n";
	print DRIVER "\t\t\t\t\t\tCf([j C_fit{j,2}]) = Cf([j C_fit{j,2}])*C_fit{j,1}/sum(Cf([j C_fit{j,2}]));\n";
	print DRIVER "\t\t\t\t\t\tconverged = 0;\n";
	print DRIVER "\t\t\t\t\tend\n";
	print DRIVER "\t\t\t\tend\n";
	print DRIVER "\t\t\tend\n";
	print DRIVER "\t\tend\n";
	
    if($include_generic_neg && $include_generic_pos){
		if($generic_positive_ions_corr ne ''){
			print DRIVER "\t\tif abs(sum(Cf(positives))-sum(Cf(negatives)))/max(Cf($n_generic_pos),c_min_th) > difftol\n";
			print DRIVER "\t\t\tif sum(Cf(negatives))-sum(Cf(positives))+Cf($n_generic_pos)>0\n";
			print DRIVER "\t\t\t\tCf($n_generic_pos) = sum(Cf(negatives))-sum(Cf(positives))+Cf($n_generic_pos);\n";
			print DRIVER "\t\t\telse\n";
			print DRIVER "\t\t\t\tCf($n_generic_neg) = sum(Cf(positives))-Cf($n_generic_pos)-sum(Cf(negatives))+Cf($n_generic_neg);\n";
			print DRIVER "\t\t\t\tCf($n_generic_pos) = 0;\n";
			print DRIVER "\t\t\tend\n";
			print DRIVER "\t\t\tconverged = 0;\n";
			print DRIVER "\t\tend\n\n";
		}elsif($generic_negative_ions_corr ne ''){
			print DRIVER "\t\tif abs(sum(Cf(positives))-sum(Cf(negatives)))/max(Cf($n_generic_neg),c_min_th) > difftol\n";
			print DRIVER "\t\t\tif sum(Cf(positives))-sum(Cf(negatives))+Cf($n_generic_neg)>0\n";
			print DRIVER "\t\t\t\tCf($n_generic_neg) = sum(Cf(positives))-sum(Cf(negatives))+Cf($n_generic_neg);\n";
			print DRIVER "\t\t\telse\n";
			print DRIVER "\t\t\t\tCf($n_generic_pos) = sum(Cf(negatives))-Cf($n_generic_neg)-sum(Cf(positives))+Cf($n_generic_pos);\n";
			print DRIVER "\t\t\t\tCf($n_generic_neg) = 0;\n";
			print DRIVER "\t\t\tend\n";
			print DRIVER "\t\t\tconverged = 0;\n";
			print DRIVER "\t\tend\n\n";
		}elsif($generic_positive_ions ne ''){
			print DRIVER "\t\tif abs(Cf($n_generic_pos)-sum(Cf(negatives)))/max(Cf($n_generic_pos),c_min_th) > difftol\n";
			print DRIVER "\t\t\tCf($n_generic_pos) = sum(Cf(negatives));\n";
			print DRIVER "\t\t\tconverged = 0;\n";
			print DRIVER "\t\tend\n\n";
		}elsif($generic_negative_ions ne ''){
			print DRIVER "\t\tif abs(Cf($n_generic_neg)-sum(Cf(positives)))/max(Cf($n_generic_neg),c_min_th) > difftol\n";
			print DRIVER "\t\t\tCf($n_generic_neg) = sum(Cf(positives));\n";
			print DRIVER "\t\t\tconverged = 0;\n";
			print DRIVER "\t\tend\n\n";
		}
	}
	print DRIVER "\t\tC0 = Cf;\n";
	print DRIVER "\t\tC00 = [C00; C(2:end,:)];\n";
	print DRIVER "\t\tT00 = [T00; T(2:end)];\n";
	print DRIVER "\tend\n";
	print DRIVER "\tif ~C0_in && numel(Tmax)==1\n";
	print DRIVER "\t\tC = C00(2:end,:);\n";
	print DRIVER "\t\tT = T00(2:end);\n";
	print DRIVER "\telse\n";
	print DRIVER "\t\tC = C00;\n";
	print DRIVER "\t\tT = T00;\n";
	print DRIVER "\tend\n";
	print DRIVER "\tfor i=n_fun\n";
	print DRIVER "\t\tC(:,i) = eval(C_fun_str_3{i});\n";
	print DRIVER "\tend\n\n";

	print DRIVER "\% Printing table of neutral concentrations\n\tif(c_neutr)\n";
	$ncols = 1;
	for($i=1;$i<$n_neutral_mols;$i++){
		$ncols = $ncols*($n_max_type[$neutral_mols[$i]]+1);
	}
	print DRIVER "\t\tt0 = zeros($n_max_type[0],$ncols);\n";
	print DRIVER "\t\tfor i = 1:length(neutrals)\n\t\t\tt0(table_0{i}(1),table_0{i}(2)) = neutrals(i);\n\t\tend\n";
	print DRIVER "\t\tcfid = fopen(fname3, 'w');\n";
	print DRIVER "\t\tfprintf(cfid,'\%\% ";
	$line = '';
	for($icol=1;$icol<=$ncols;$icol++){
		$kmol = $icol-1;
		$iline = '';
		for($i=1;$i<$n_neutral_mols;$i++){
			$imol = $neutral_mols[$n_neutral_mols-$i];
			$nmol = 1;
			for($j=$i+1;$j<$n_neutral_mols;$j++){
				$jmol = $neutral_mols[$n_neutral_mols-$j];
				$nmol = $nmol*($n_max_type[$jmol]+1);
			}
			$iline = int($kmol/$nmol) . "$molecule_name[$imol]$iline";
			$kmol = $kmol-int($kmol/$nmol)*$nmol;
		}
		$line = "$line, '$iline'";
		print DRIVER "\%-9s ";
	}
	print DRIVER "\\n'$line);\n";
	print DRIVER "\t\tfor i=1:size(t0,1)\n\t\t\tfor j=1:size(t0,2)\n";
	print DRIVER "\t\t\t\tif t0(i,j)<1\n\t\t\t\t\tfprintf(cfid,'	  nan ');\n";
	print DRIVER "\t\t\t\telse\n\t\t\t\t\tfprintf(cfid,'\%.3e ',Cf(t0(i,j))*1e-6);\n";
	print DRIVER "\t\t\t\tend\n\t\t\tend\n\t\t\tfprintf(cfid,'\\n');\n\t\tend\n\t\tfclose(cfid);\n\tend\n\n";
	
	if($include_negative_ion_terms){
		print DRIVER "\% Printing table of negative concentrations\n\tif(c_neg)\n";
		$ncols = 1;
		for($i=1;$i<$n_neutral_mols;$i++){
			$ncols = $ncols*($n_max_type_neg[$neutral_mols[$i]]+1);
		}
		print DRIVER "\t\ttn = zeros($n_max_type_neg[0],$ncols);\n";
		print DRIVER "\t\tfor i = 1:length(negatives)\n\t\t\ttn(table_neg{i}(1),table_neg{i}(2)) = negatives(i);\n\t\tend\n";
		print DRIVER "\t\tcfid = fopen(fname4, 'w');\n";
		print DRIVER "\t\tfprintf(cfid,'\%\% ";
		$line = '';
		for($icol=1;$icol<=$ncols;$icol++){
			$kmol = $icol-1;
			$iline = '';
			for($i=1;$i<$n_neutral_mols;$i++){
				$imol = $neutral_mols[$n_neutral_mols-$i];
				$nmol = 1;
				for($j=$i+1;$j<$n_neutral_mols;$j++){
					$jmol = $neutral_mols[$n_neutral_mols-$j];
					$nmol = $nmol*($n_max_type_neg[$jmol]+1);
				}
				$iline = int($kmol/$nmol) . "$molecule_name[$imol]$iline";
				$kmol = $kmol-int($kmol/$nmol)*$nmol;
			}
			$line = "$line, '$iline'";
			print DRIVER "\%-9s ";
		}
		print DRIVER "\\n'$line);\n";
		print DRIVER "\t\tfor i=1:size(tn,1)\n\t\t\tfor j=1:size(tn,2)\n";
		print DRIVER "\t\t\t\tif tn(i,j)<1\n\t\t\t\t\tfprintf(cfid,'	  nan ');\n";
		print DRIVER "\t\t\t\telse\n\t\t\t\t\tfprintf(cfid,'\%.3e ',Cf(tn(i,j))*1e-6);\n";
		print DRIVER "\t\t\t\tend\n\t\t\tend\n\t\t\tfprintf(cfid,'\\n');\n\t\tend\n\t\tfclose(cfid);\n\tend\n\n";
	}
	
	if($include_positive_ion_terms){
		print DRIVER "\% Printing table of positive concentrations\n\tif(c_pos)\n";
		$ncols = 1;
		for($i=1;$i<$n_neutral_mols;$i++){
			$ncols = $ncols*($n_max_type_pos[$neutral_mols[$i]]+1);
		}
		print DRIVER "\t\ttp = zeros($n_max_type_pos[0],$ncols);\n";
		print DRIVER "\t\tfor i = 1:length(positives)\n\t\t\ttp(table_pos{i}(1),table_pos{i}(2)) = positives(i);\n\t\tend\n";
		print DRIVER "\t\tcfid = fopen(fname5, 'w');\n";
		print DRIVER "\t\tfprintf(cfid,'\%\% ";
		$line = '';
		for($icol=1;$icol<=$ncols;$icol++){
			$kmol = $icol-1;
			$iline = '';
			for($i=1;$i<$n_neutral_mols;$i++){
				$imol = $neutral_mols[$n_neutral_mols-$i];
				$nmol = 1;
				for($j=$i+1;$j<$n_neutral_mols;$j++){
					$jmol = $neutral_mols[$n_neutral_mols-$j];
					$nmol = $nmol*($n_max_type_pos[$jmol]+1);
				}
				$iline = int($kmol/$nmol) . "$molecule_name[$imol]$iline";
				$kmol = $kmol-int($kmol/$nmol)*$nmol;
			}
			$line = "$line, '$iline'";
			print DRIVER "\%-9s ";
		}
		print DRIVER "\\n'$line);\n";
		print DRIVER "\t\tfor i=1:size(tp,1)\n\t\t\tfor j=1:size(tp,2)\n";
		print DRIVER "\t\t\t\tif tp(i,j)<1\n\t\t\t\t\tfprintf(cfid,'	  nan ');\n";
		print DRIVER "\t\t\t\telse\n\t\t\t\t\tfprintf(cfid,'\%.3e ',Cf(tp(i,j))*1e-6);\n";
		print DRIVER "\t\t\t\tend\n\t\t\tend\n\t\t\tfprintf(cfid,'\\n');\n\t\tend\n\t\tfclose(cfid);\n\tend\n\n";
	}
	
	print DRIVER "\tif ~no_j\n";
	print DRIVER "\t\tJ_out = nan(1,length(T));\n";
	print DRIVER "\t\tfor i=1:length(T)\n";
	if(!$variable_temp){
		print DRIVER "\t\t\tJ_out(i) = $j_function_name(C(i,:)*1e-6,K);\n";
	}else{
		print DRIVER "\t\t\tJ_out(i) = $j_function_name(C(i,:)*1e-6,temperature,K);\n";
	}
	print DRIVER "\t\tend\n";
	if($l_old_output){
		print DRIVER "\telse\n";
		print DRIVER "\t\tJ_out = [];\n";
	}
	print DRIVER "\tend\n";
	print DRIVER "\tif ~no_fluxes\n";
	$input_for_flux_temp=$input_for_flux;
	$input_for_flux_temp =~ s/^c,/C(end,:),/;
	print DRIVER "\t\t[flux, ~, sources, ~, flux_out, ~] = $flux_function_name($input_for_flux_temp);\n";
	print DRIVER "\t\t\% Back to cubic centimeters\n";
	print DRIVER "\t\tflux = flux*1e-6;\n\t\tsources = sources*1e-6;\n\t\tflux_out = flux_out*1e-6;\n";
	if($l_old_output){
		print DRIVER "\telse\n";
		print DRIVER "\t\tflux = [];\n\t\tout = [];\n\t\toutflux_matrix = [];\n\t\tsources = [];\n\t\tform = [];\n";
	}
	print DRIVER "\tend\n\n";
	print DRIVER "\tC = C*1e-6;\n\tCf = Cf*1e-6;\n";
	
	
	print DRIVER "\t% printing out source file for constant monomer concentrations\n";
	print DRIVER "\tif consts_out && converged\n";
	print DRIVER "\t\tcfid = fopen(fname2c, 'w');\n";
	print DRIVER "\t\tfor i=monomers\n";
	print DRIVER "\t\t\tfprintf(cfid,'constant \%s \%f\\n',clust{i}, Cf(i));\n";
	print DRIVER "\t\tend\n";
	print DRIVER "\t\tfclose(cfid);\n";
	print DRIVER "\tend\n\n";
	print DRIVER "\tif ~no_fluxes\n";
	print DRIVER "\t\t% printing out source file for monomer sources\n";
	print DRIVER "\t\tif sources_out && converged\n";
	print DRIVER "\t\t\tsfid = fopen(fname2, 'w');\n";
	print DRIVER "\t\t\tfor i=monomers\n";
	print DRIVER "\t\t\t\tfprintf(sfid,'source \%s \%f\\n',clust{i}, sources(i));\n";
	print DRIVER "\t\t\tend\n";
	print DRIVER "\t\t\tfclose(sfid);\n";
	print DRIVER "\t\tend\n\n";
	
	$temp_val = max($n_max_type[0],$n_max_type_neg[0],$n_max_type_pos[0]);
	if(@cs_cluster){
		$temp_val = max($temp_val,$cs_cluster[0]);
	}
	if(@cs_cluster_neg){
		$temp_val = max($temp_val,$cs_cluster_neg[0]);
	}
	if(@cs_cluster_pos){
		$temp_val = max($temp_val,$cs_cluster_pos[0]);
	}
	if($corr_negative_mol[0] !~ /^\s*$/ || $corr_positive_mol[0] !~ /^\s*$/){
		$temp_val += 1;
	}
	$temp_val = $temp_val*2+1;
	print DRIVER "\t\tout = zeros($max_cluster_number,$temp_val,4);\n";
	print DRIVER "\t\toutflux_matrix = zeros($max_cluster_number,$max_cluster_number);\n";
	if($use_coag_to_outgoing && ($include_generic_neg || $include_generic_pos)){
		print DRIVER "\t\tfor i=[1:" . ($max_cluster-1) . "," . ($max_cluster+1) . ":$max_cluster_number]\n";
	}elsif($use_coag_to_outgoing){
		print DRIVER "\t\tfor i=1:" . ($max_cluster-1) . "\n";
	}else{
		print DRIVER "\t\tfor i=1:$max_cluster_number\n";
	}
	if($use_coag_to_outgoing && ($include_generic_neg || $include_generic_pos)){
		print DRIVER "\t\t\tfor j=[1:" . ($max_cluster-1) . "," . ($max_cluster+1) . ":$max_cluster_number]\n";
	}elsif($use_coag_to_outgoing){
		print DRIVER "\t\t\tfor j=1:" . ($max_cluster-1) . "\n";
	}else{
		print DRIVER "\t\t\tfor j=1:$max_cluster_number\n";
	}
	print DRIVER "\t\t\t\tk = " . $molecule_name[0] . "_in_clust(i)+" . $molecule_name[0] . "_in_clust(j)+1;\n";
	print DRIVER "\t\t\t\tout(i,k,:) = out(i,k,:)+flux_out(i,j,:);\n";
	print DRIVER "\t\t\t\toutflux_matrix(i,j) = sum(flux_out(i,j,:));\n";
	print DRIVER "\t\t\tend\n";
	print DRIVER "\t\tend\n";

# Variable 'form' is not printed to the driver, for now, since nobody is probably using it
#	$temp_val = ($temp_val-1)/2;
#	print DRIVER "\t\tform=zeros(1,$temp_val);\n";
#	if($use_coag_to_outgoing && ($include_generic_neg || $include_generic_pos)){
#		print DRIVER "\t\tfor i=[1:" . ($max_cluster-1) . "," . ($max_cluster+1) . ":$max_cluster_number]\n";
#	}elsif($use_coag_to_outgoing){
#		print DRIVER "\t\tfor i=1:" . ($max_cluster-1) . "\n";
#	}else{
#		print DRIVER "\t\tfor i=1:$max_cluster_number\n";
#	}
#	if($use_coag_to_outgoing && ($include_generic_neg || $include_generic_pos)){
#		print DRIVER "\t\t\tfor j=[1:" . ($max_cluster-1) . "," . ($max_cluster+1) . ":$max_cluster_number]\n";
#	}elsif($use_coag_to_outgoing){
#		print DRIVER "\t\t\tfor j=1:" . ($max_cluster-1) . "\n";
#	}else{
#		print DRIVER "\t\t\tfor j=1:$max_cluster_number\n";
#	}
#	print DRIVER "\t\t\t\tif " . $molecule_name[0] . "_in_clust(i)<" . $molecule_name[0] . "_in_clust(j)\n";
#	print DRIVER "\t\t\t\t\tform(" . $molecule_name[0] . "_in_clust(j))=form(" . $molecule_name[0] . "_in_clust(j))+flux(i,j)-flux(j,i);\n";
#	print DRIVER "\t\t\t\tend\n";
#	print DRIVER "\t\t\tend\n";
#	print DRIVER "\t\tend\n";
#	print DRIVER "\t\tform = form/2;\n\n";

	print DRIVER "\t\% Printing the flux matrix\n\t\tif(fl_out)\n";
	print DRIVER "\t\t\tfid=fopen(fname6,'w');\n\t\t\tfprintf(fid,'\%\% ');\n\t\t\tfor i=1:length(clust_flux)\n\t\t\t\tfprintf(fid,'\%s ',clust_flux{i});\n\t\t\tend\n";
	print DRIVER "\t\t\tfprintf(fid,'\\n');\n";
	if($keep_boundary_clusters){
		# Print also the "true" cluster names to distinguish the boundary clusters when the fluxes are tracked
		print DRIVER "\t\t\tfprintf(fid,'\%\% ');\n\t\t\tfor i=1:length(clust)\n\t\t\t\tfprintf(fid,'\%s ',clust{i});\n\t\t\tend\n";
		print DRIVER "\t\t\tfprintf(fid,'\\n');\n";
	}
	print DRIVER "\t\t\tfor i=1:size(flux,1)\n\t\t\t\tfor j=1:size(flux,2)\n\t\t\t\t\tfprintf(fid,'\%.6e ',flux(i,j));\n\t\t\t\tend\n\t\t\t\tfprintf(fid,'\\n');\n\t\t\tend\n\t\t\tfclose(fid);\n\t\tend\n\n";

	print DRIVER "\t\% Printing the outflux matrix\n\t\tif(outmat)\n";
	print DRIVER "\t\t\tfid=fopen(fname7,'w');\n\t\t\tfprintf(fid,'\%\% ');\n\t\t\tfor i=1:length(clust)\n\t\t\t\tfprintf(fid,'\%s ',clust{i});\n\t\t\tend\n\t\t\tfprintf(fid,'\\n');\n";
	print DRIVER "\t\t\tfor i=1:size(outflux_matrix,1)\n\t\t\t\tfor j=1:size(outflux_matrix,2)\n\t\t\t\t\tfprintf(fid,'\%.6e ',outflux_matrix(i,j));\n\t\t\t\tend\n\t\t\t\tfprintf(fid,'\\n');\n\t\t\tend\n\t\t\tfclose(fid);\n\t\tend\n\n";
	print DRIVER "\tend\n";
	

	if(! $l_save_outgoing){
		print DRIVER "\tC = C(:,1:$size_C_out);\n";
		print DRIVER "\tCf = Cf(1:$size_C_out);\n";
	}
	if(!$l_old_output){
		print DRIVER "\tif nargout>5\n";
		print DRIVER "\t\toutput_opt={labels_ch, clust_flux, J_out, flux, outflux_matrix, out, sources};\n";
		print DRIVER "\t\tvarargout=output_opt(1:nargout-5);\n";
		print DRIVER "\tend\n";
	}
	print DRIVER "end";


# Done with the driver routine
}

close(DRIVER);
if(!$lsilent){
    print "\n###########################################################\n";
    if($lhydrate_average==1){
        print "Done printing the output files. RH = $rh %, P(water) = $pw Pa\n";
    }else{
        print "Done printing the output files.\n";
    }
    print "###########################################################\n";
}

################################################################
####                 END MAIN PROGRAM                       ####
################################################################


################################################################################
################################################################################
##   15. Subroutines                                                          ##
################################################################################
################################################################################

#######################################################################################################
# This subroutine combines two labels into one; if one of the clusters is positive and one is negative,
# it assumes that they recombine into a neutral molecule. If they are ions of the same sign, they can't
# be combined.
# The subroutine returns 3 values: 1) the label of the combined cluster, 2) a logical called valid_coll,
# which is 1 if the collision can happen, and 0 if it can't, which is the case when the colliding clusters
# are ions of the same sign, or we are disabling certain collisions, and 3) a logical called valid_evap,
# which is 1 if the cluster can evaporate back to the 2 original clusters, and 0 if it can't, which is
# true in the case where ions of opposite sign recombine or if cluster evaporations are forbidden.
#######################################################################################################

# combine_labels: ($value,$valid_coll,$valid_evap,$valid) = combine_labels($cluster1,$cluster2)
sub combine_labels(){
	my($cluster1,$cluster2,@nmols,$value,$valid_coll,$valid_evap);
	my($lcontinue,$lrec,$neg_clus,$pos_clus,$neutral_clus,@temp_array_neg,@temp_array_pos, @temp_array_neutral,@nmols1,@nmols2,$imol,$lout,$valid,$lfound,$i);
	$cluster1=$_[0];
	$cluster2=$_[1];

#	die "\nCluster numbers not defined! $cluster1 $cluster2\n\n" if ($cluster1 !~ /^\d+$/ || $cluster2 !~ /^\d+$/);

	$value='Undefined';
	$valid_coll=0;
	$valid_evap=0;
	$valid=0;

	$lcontinue=1;
	
	
	
	# First see if this is a collision between two charger ions -> that doesn't lead to a cluster
	if(($cluster1 > $max_cluster) &&  ($cluster2 > $max_cluster)){
		# the collision can still happen if the chargers have different polarities
		if($cluster1 != $cluster2){
			$valid_coll=1;
		}
		$lcontinue=0;
	
	# Then see if we are disabling (some) non-monomer collisions
	}elsif($disable_nonmonomers || $#nonmonomer_collisions_only>=0){
		# If so, check if this is a recombination in case non-monomer collisions are still allowed for those
		$lrec = 0;
		if($enable_rec_nonmonomers){
			if(($lnegative[$cluster1] && $lpositive[$cluster2]) || ($lpositive[$cluster1] && $lnegative[$cluster2])){
				$lrec = 1;
			}
		}
		# Now, check if this is a non-monomer process if this is is a collision type where they are disabled
		if(!$lrec){
			if(($cluster1 <= $max_cluster) &&  ($cluster2 <= $max_cluster)){
				$lmonomer1=$lmonomer[$cluster1];
				$lmonomer2=$lmonomer[$cluster2];
				if(! $lmonomer1 && ! $lmonomer2){
					$lcontinue=0;
					for($i=0;$i<=$#nonmonomer_collisions_only;$i++){
						if($i==$cluster1 || $i==$cluster2){
							$lcontinue=1;
							last;
						}
					}
				}
			}
		}
	}

	# Now some less trivial cases:
	if($lcontinue){

		# first the case where one of the clusters is negative and one is positive
		if(($lnegative[$cluster1] && $lpositive[$cluster2]) || ($lpositive[$cluster1] && $lnegative[$cluster2])){
			$valid_coll=1;
			# this can't evaporate back to the original pieces any more!
			$valid_evap=0;

			# which is which?
			if($lnegative[$cluster1]){
				$neg_clus=$cluster1;
				$pos_clus=$cluster2;
			}else{
				$neg_clus=$cluster2;
				$pos_clus=$cluster1;
			}

			# find the ions and change them into neutral molecules
			
			# first the negative ion
			@temp_array_neg=@{ $clust_comp[$neg_clus] };
			$wanted_mol=0;
			$wanted_mol++ until($wanted_mol > $nmol_types || ($temp_array_neg[$wanted_mol] > 0 && $charge[$wanted_mol] < 0));
			if($wanted_mol > $nmol_types){
				die "\nCan't find the charged molecule in the negative cluster $label[$neg_clus]!\n\n";
			}
			# is this ion described by a missing proton?
			if($missing_proton>=0 && $temp_array_neg[$missing_proton] == 1){
				$temp_array_neg[$missing_proton] = 0;
			}else{
				# otherwise find the corresponding neutral molecule
				$corr_mol=$mol_num_from_name{$corr_neutral_mol[$wanted_mol]};
				# change this into a neutral cluster
				$temp_array_neg[$wanted_mol]-=1;
				$temp_array_neg[$corr_mol]+=1;
			}

			# then the positive ion
			@temp_array_pos=@{ $clust_comp[$pos_clus] };
			$temp_array_pos[$proton]-=1;

			# then combine the labels

			for($imol=0;$imol<$nmol_types;$imol++){
				$nmols[$imol]=$temp_array_neg[$imol]+$temp_array_pos[$imol];
				# If we get a negative number for some molecule type, something is wrong!
				if($nmols[$imol]<0){
					$value='Undefined';
					$valid_coll=0;
					$valid_evap=0;
					$lcontinue = 0;
					last;
				}
			}

		# if they both are ions of the same sign, they are not allowed to collide
		}elsif(($lnegative[$cluster1] && $lnegative[$cluster2]) || ($lpositive[$cluster1] && $lpositive[$cluster2])){

			$value='Undefined';
			$valid_coll=0;
			$valid_evap=0;
			$lcontinue = 0;

		# if the collision involves either two neutral clusters or a neutral cluster and an ion, 
		# the labels are combined by simply counting the sum of all the molecules
		}else{
			
			$valid_coll=1;
			$valid_evap=1;

			@nmols1=@{ $clust_comp[$cluster1] };
			@nmols2=@{ $clust_comp[$cluster2] };
			

			for($imol=0;$imol<$nmol_types;$imol++){
			
				$nmols[$imol]=$nmols1[$imol]+$nmols2[$imol];
				# If we try to charge something that can't be charged, we might get negative molecule numbers
				if($nmols[$imol]<0){
					$value='Undefined';
					$valid_coll=0;
					$valid_evap=0;
					$lcontinue = 0;
				}
			}

			# If there's a proton or missing proton, there needs to be a molecule that can accept or donate one
			if($proton>=0 && $nmols[$proton]>0){
				$lfound = 0;
				for($imol=0;$imol<$nmol_types;$imol++){
					if($nmols[$imol] > 0){
						if($charge[$imol] == 0 && $corr_positive_mol[$imol] ne ''){
							$lfound=1;
						}
					}
				}
				if(!$lfound){
					$value='Undefined';
					$valid_coll=0;
					$valid_evap=0;
					$lcontinue = 0;
				}
			}elsif($missing_proton>=0 && $nmols[$missing_proton]>0){
				$lfound = 0;
				for($imol=0;$imol<$nmol_types;$imol++){
					if($nmols[$imol] > 0){
						if($charge[$imol] == 0 && $corr_negative_mol[$imol] ne ''){
							$lfound=1;
						}
					}
				}
				if(!$lfound){
					$value='Undefined';
					$valid_coll=0;
					$valid_evap=0;
					$lcontinue = 0;
				}
			}
		}
	}
		
	# If the collision can happen, make a label for the product.
	if($lcontinue){
		$value=&create_label(\@nmols);

		# now, let's see if we are disabling collisions resulting in clusters outside of the system
		$valid=&check_validity($value);

		if(!$valid){
			$valid_evap=0;
			if($disable_excluded){
				$value='Undefined';
				$valid_coll=0;
				if($l_print_boundary){
					print "Not using boundary collision $label[$cluster1] + $label[$cluster2]\n";
				}
			}elsif($disable_excluded_ionization && (!$lneutral_cluster[$cluster1] || !$lneutral_cluster[$cluster2])){
				$value='Undefined';
				$valid_coll=0;
				if($l_print_boundary){
					print "Not using boundary collision $label[$cluster1] + $label[$cluster2]\n";
				}
			}
		}
	}
	
	if($valid_evap){
		# If one of the collision partners is a charger ion, the product can't evaporate back
		if($cluster1 > $max_cluster ||  $cluster2 > $max_cluster){
			$valid_evap = 0;
		}
	
		# Check if evaporations are disabled completely ...
		if($disable_evap){
			$valid_evap=0;
		# ... or just for this specific cluster ...
		}elsif($disable_evap_only[&get_cluster_number($value)]){
			$valid_evap=0;
		# ... or for fragmentation into two clusters ...
		}elsif($disable_nonmonomer_evaps){
			$lmonomer1=$lmonomer[$cluster1];
			$lmonomer2=$lmonomer[$cluster2];
			if(! $lmonomer1 && ! $lmonomer2){
				$valid_evap = 0;
			}
		}
	}


#	print"Combined $label[$cluster1] and $label[$cluster2] into $value, valid_evap is $valid_evap, valid_coll is $valid_coll\n";
	#print"Prevented collision of $label[$cluster1] and $label[$cluster2]\n" if(!$valid_coll);
	#print"Prevented evaporation of $value into $label[$cluster1] and $label[$cluster2]\n" if(!$valid_evap && $valid_coll);
	
	return ($value,$valid_coll,$valid_evap,$valid);
}


######################################################################################################################
## This subroutine checks if a cluster resulting from a collision or an ionization can get out of the system 
## (given how we have defined to let stuff get out), or if we will bring it back to the system boundary.
## It takes in the label of the cluster that is to be checked and returns the label of the cluster 
## after doing the check; if the cluster was allowed to get out, the label is the same as the input label,
## and if it is brougth back to the system, the label is the label for the cluster on the boundary.
## This also returns $lout, which is 1, 2 or 3 if the cluster got out, and 0 if it was brought back,
## and a hash array of how many molecules of each type were removed when bringing the cluster back to the boundary.
######################################################################################################################

# check_boundary: ($new_label,$lout,%nmonomers) = check_boundary($label0)
sub check_boundary(){
	my($label0,$valid,@temp_array,$n_first,@n_max,$lout,$new_label,$valid_new,%nmonomers);
	my($imol,$jmol,$element_name,@rules,$n_rules,$irule,$i);
	my($n_acid,$n_acid_other,$n_base,$n_base_other,$n_neutral,$l_remove_acids,$acid_min,$base_min,$lneg,$lpos);
	my($l_tried_acid_loop,$l_tried_base_loop,$diff,$n_neutral_old,$charge_clus);
	my($nmols_removable_max,$imol_max,$nmols_removable,$nmols_nonremovable);

	$label0=$_[0];
	$new_label=$label0;
	$lout=0;

	for($imol=0;$imol<$nmol_types;$imol++){
		$nmonomers{$molecule_name[$imol]}=0;
	}

	$valid=&check_validity($label0);
	if($valid){
		die "Cluster $label0 is inside the system, why is it being brought to the boundary?\n";
	}
	
	# see if we are allowing this to get out
	($ref,$comp_ok)=&determine_cluster_composition($label0);
	@temp_array=@$ref;
	# these are the criteria for neutrals getting out of the simulation
	@rules = @nucl_rules;
	$n_rules = $n_nucl_rules;
	@n_max=@n_max_type;
	$charge_clus = 0;
	#  but if this is a charged cluster, the criteria are different 
	for($imol=0;$imol<$nmol_types;$imol++){
		if($charge[$imol] == -1 && $temp_array[$imol] > 0){
			@rules = @nucl_rules_neg;
			$n_rules = $n_nucl_rules_neg;
			@n_max=@n_max_type_neg;
			$charge_clus -= $temp_array[$imol];
			last;   
		}elsif($charge[$imol] == 1 && $temp_array[$imol] > 0){
			@rules = @nucl_rules_pos;
			$n_rules = $n_nucl_rules_pos;
			@n_max=@n_max_type_pos;
			$charge_clus += $temp_array[$imol];
			last;
		}
	}

	# now we go through the rules to see if any of them are satisfied
	for($irule=0;$irule<$n_rules;$irule++){
		if($charge_clus<0){
			$lout = 2;
#			print "charge:$charge_clus,\t@n_max_type_neg\n;"
		}elsif($charge_clus>0){
			$lout = 3;
#			print "charge:$charge_clus,\t@n_max_type_pos\n;"
		}else{
			$lout = 1;
#			print "charge:$charge_clus,\t@n_max_type\n;"
		}
		for($imol=0;$imol<$nmol_types;$imol++){
			if($temp_array[$imol]<$rules[$irule][$imol]){
				$lout = 0;
			}
		}
		if($lout>0){
			last;
		}
	}
	
	# If the cluster didn't get out, we need to bring it back to the system
	if($lout==0){
		# First check if there are more molecules of some type than in ANY allowed clusters
		
		for($imol=0;$imol<$nmol_types;$imol++){
			if($charge_clus==0 && $temp_array[$imol] > $n_max_type[$imol]){
				$nmonomers{$molecule_name[$imol]} += $temp_array[$imol]-$n_max_type[$imol];
				$temp_array[$imol] = $n_max_type[$imol];
			}elsif($charge_clus<0 && $temp_array[$imol] > $n_max_type_neg[$imol]){
				$nmonomers{$molecule_name[$imol]} += $temp_array[$imol]-$n_max_type_neg[$imol];
				$temp_array[$imol] = $n_max_type_neg[$imol];
			}elsif($charge_clus>0 && $temp_array[$imol] > $n_max_type_pos[$imol]){
				$nmonomers{$molecule_name[$imol]} += $temp_array[$imol]-$n_max_type_pos[$imol];
				$temp_array[$imol] = $n_max_type_pos[$imol];
			}
		}
		$new_label = &create_label(\@temp_array);
		$valid=&check_validity($new_label);
	}
	
	# If this didn't help, try to bring it to the boundary one molecule at a time
	
	# First try using the acid and base strengths if they are given
	if($lout==0 && !$valid && $l_strength_neutral == 1){
		# First find out the number of acids and bases in the cluster
		$n_acid = 0;
		$n_base = 0;
		$n_acid_other = 0;
		$n_base_other = 0;
		$n_neutral = 0;
		for($imol=0;$imol<$nmol_types;$imol++){
			if($temp_array[$imol] > 0){
				# Number of neutral molecules in total
				if($charge[$imol]==0){
					$n_neutral += $temp_array[$imol];
				}
				if($acid_strength[$imol]>0){
					# Number of acids that can ...
					if($l_can_be_lost_bound[$imol] || $imol == $proton){
						$n_acid += $temp_array[$imol];
					}else{
					# ... and can't be lost
						$n_acid_other += $temp_array[$imol];
					}
					if($imol == $proton){
						# the proton forms an acid together with a molecule that would otherwise be a base
						$n_base_other -= 1;
						$n_neutral -= 1;
					}
				}
				if($base_strength[$imol]>0){
					# Number of bases that can ...
					if($l_can_be_lost_bound[$imol] || $imol == $missing_proton){
						$n_base += $temp_array[$imol];
					}else{
					# ... and can't be lost
						$n_base_other += $temp_array[$imol];
					}
					if($imol == $missing_proton){
						# the "missing proton" forms a base together with a molecule that would otherwise be an acid
						$n_acid_other -= 1;
						$n_neutral -= 1;
					}
				}
			}
		}
#		print "a:$n_acid, ao:$n_acid_other, b:$n_base, bo:$n_base_other\n";
		if($n_acid_other<0){
			$n_acid += $n_acid_other;
			$n_acid_other = 0;
		}
		if($n_base_other<0){
			$n_base += $n_base_other;
			$n_base_other = 0;
		}
#		print "a:$n_acid, ao:$n_acid_other, b:$n_base, bo:$n_base_other\n";
		if($n_acid+$n_acid_other > $n_base+$n_base_other){
			$l_remove_acids = 1;
		}else{
			$l_remove_acids = 0;
		}
		$acid_min = 0;
		$base_min = 0;
#		print "\n\n$label0\n";
		$n_neutral_old = $n_neutral;
		$l_tried_acid_loop = 0;
		$l_tried_base_loop = 0;
		$diff = 0;
		while(!$valid && $n_neutral>$diff){
#			print "$n_acid+$n_acid_other+$diff > $n_base+$n_base_other: ".($n_acid+$n_acid_other+$diff > $n_base+$n_base_other)."\n";
			# If we have more acids than bases, start removing acids ...
			if($l_remove_acids){
				$l_tried_acid_loop = 1;
				# ... if we have any neutral ones left
				if($acid_min>$acid_max){
					last;
				}
				ACID_MOL_LOOP: for($imol=0;$imol<$nmol_types;$imol++){
#					print "acid loop:$molecule_name[$imol]\n";
					if(!$l_can_be_lost_bound[$imol]){
						next;
					}
					# Start from the weakest acid in the cluster, but only if it is neutral
					if(($temp_array[$imol]>0) && ($acid_strength[$imol]==$acid_min) && $charge[$imol]==0){
						# Remove molecules one by one ...
						while($temp_array[$imol]>0){
#							print "removing $molecule_name[$imol]\n";
							$temp_array[$imol] -= 1;
							$n_neutral -= 1;
							$nmonomers{$molecule_name[$imol]} += 1;
							if($acid_strength[$imol]>0){
								$n_acid -= 1;
							}
							if($base_strength[$imol]>0){
								$n_base -= 1;
							}
							if($n_acid+$n_acid_other <= $n_base+$n_base_other+$diff){
								$l_remove_acids = 0;
							}
							$new_label = &create_label(\@temp_array);
#							print "->$new_label\n";
							$valid=&check_validity($new_label);
							# ... until we have a valid cluster or there are no longer more acids than bases left
							if($valid || !$l_remove_acids){
								last ACID_MOL_LOOP;
							}
						}
					}
				}
				# Move to the next stronger acid, if we are continuing to remove acids
				if($l_remove_acids){
					$acid_min += 1;
				}else{
					$base_min = 0;
				}
			# If we have more or as many bases than acids, start removing bases ...
			}else{
				$l_tried_base_loop = 1;
				# ... if we have any neutral ones left
				if($base_min>$base_max){
					last;
				}
				BASE_MOL_LOOP: for($imol=0;$imol<$nmol_types;$imol++){
#					print "base loop: $molecule_name[$imol]\n";
					if(!$l_can_be_lost_bound[$imol]){
						next;
					}
					# Start from the weakest base in the cluster, but only if it is neutral
					if(($temp_array[$imol]>0) && ($base_strength[$imol]==$base_min) && $charge[$imol]==0){
						# Remove molecules one by one ...
						while($temp_array[$imol]>0){
#							print "removing $molecule_name[$imol]\n";
							$temp_array[$imol] -= 1;
							$n_neutral -= 1;
							$nmonomers{$molecule_name[$imol]} += 1;
							if($base_strength[$imol]>0){
								$n_base -= 1;
							}
							if($acid_strength[$imol]>0){
								$n_acid -= 1;
							}
							if($n_acid+$n_acid_other+$diff > $n_base+$n_base_other){
								$l_remove_acids = 1;
							}
							$new_label = &create_label(\@temp_array);
#							print "->$new_label\n";
							$valid=&check_validity($new_label);
							# ... until we have a valid cluster or there are more acids than bases left
							if($valid || $l_remove_acids){
								last BASE_MOL_LOOP;
							}
						}
					}
				}
				if(!$l_remove_acids){
					$base_min += 1;
				}else{
					$acid_min = 0;
				}
			}
#			if($n_neutral<$n_neutral_old){
#				$n_neutral_old = $n_neutral;
#			}elsif(($l_remove_acids && $l_tried_acid_loop && $acid_min>$acid_max) || (!$l_remove_acids && $l_tried_base_loop && $base_min>$base_max)){
#				$diff += 1;
#				if($l_remove_acids){
#					$l_remove_acids = 0;
#				}else{
#					$l_remove_acids = 1;
#				}
#				$l_tried_acid_loop = 0;
#				$l_tried_base_loop = 0;
#			}
#			print "$valid, $n_neutral, $diff\n";
		}
	}
	
	# If no strengths are given, or the previous attempt didn't work, remove neutral molecules
	# according to the molecular content, starting from the compound with the highest molecule number
	if ($lout==0 && !$valid){
		$nmols_removable_max = 0;
		$imol_max = -1;
		while(!$valid){
			if($nmols_removable_max>0){
				#print "$new_label, removing $molecule_name[$imol_max]\n";
				$nmols_removable_max -= 1;
				$temp_array[$imol_max] -= 1;
				$nmonomers{$molecule_name[$imol_max]} += 1;
				$new_label = &create_label(\@temp_array);
				#print "->$new_label\n";
				$valid=&check_validity($new_label);
			}
			if(!$valid){
				# Find the most numerous removable neutral molecule
				for($imol=0;$imol<$nmol_types;$imol++){
					if(!$l_can_be_lost_bound[$imol] || $charge[$imol]!=0){
						next;
					}
					if($temp_array[$imol]>0){
						$nmols_removable = $temp_array[$imol];
						# If the cluster is charged and this molecule forms an ion with a proton or a missing proton,
						# subtract it from the number of removable neutral molecules of type $imol
						if($charge_clus<0 && $missing_proton >=0 && &compare_clusters($corr_negative_mol[$imol],"1$molecule_name[$imol]1$label_missing_proton")){
							if ($temp_array[$missing_proton]>0){
								$nmols_nonremovable = $temp_array[$missing_proton];
								$nmols_removable -= $nmols_nonremovable;
							}
							# Subtract other possible chargeable molecule types
							for($jmol=0;$jmol<$nmol_types;$jmol++){
								if($jmol==$imol || $charge[$imol]!=0){
									next;
								}
								if($temp_array[$jmol]>0 && &compare_clusters($corr_negative_mol[$jmol],"1$molecule_name[$jmol]1$label_missing_proton")){
									$nmols_removable += min($temp_array[$jmol],$nmols_nonremovable);
									$nmols_nonremovable -= min($temp_array[$jmol],$nmols_nonremovable);
								}
								if($nmols_nonremovable==0){
									last;
								}
							}
						}elsif($charge_clus>0 && $proton >=0 && &compare_clusters($corr_positive_mol[$imol],"1$molecule_name[$imol]1$label_proton")){
							if ($temp_array[$proton]>0){
								$nmols_nonremovable = $temp_array[$proton];
								$nmols_removable -= $nmols_nonremovable;
							}
							# Subtract other possible chargeable molecule types
							for($jmol=0;$jmol<$nmol_types;$jmol++){
								if($jmol==$imol || $charge[$imol]!=0){
									next;
								}
								if($temp_array[$jmol]>0 && &compare_clusters($corr_positive_mol[$jmol],"1$molecule_name[$jmol]1$label_proton")){
									$nmols_removable += min($temp_array[$jmol],$nmols_nonremovable);
									$nmols_nonremovable -= min($temp_array[$jmol],$nmols_nonremovable);
								}
								if($nmols_nonremovable==0){
									last;
								}
							}
						}
						if($nmols_removable > $nmols_removable_max){
							$nmols_removable_max = $nmols_removable;
							$imol_max = $imol;
						}
					}
				}
				if($nmols_removable_max==0){
					last;
				}
			}
		}
	}
	
	# If the cluster is still not back in the system, give up
	if ($lout==0 && !$valid){
		print "\nCan't bring back to boundary: $label[$iclus] + $label[$jclus] -> $label0 -> ?\n";
		die;
		$new_label = '';
	}
	return ($new_label,$lout,%nmonomers);


}


##############################################################################
## This subroutine finds the number of a cluster if it is in the system
## even if the molecules are in a different order than in the name label
##############################################################################

# get_cluster_number: $num = get_cluster_number($label1)
sub get_cluster_number(){
	my($label1,$label_new,$comp1,$comp_ok,$num);

	$label1=$_[0];
	if($use_coag_to_outgoing && $label1 eq 'cs_cluster'){
		$label1 = $cs_cluster_label;
	}elsif($use_coag_to_outgoing && $label1 eq 'cs_cluster_neg'){
		$label1 = $cs_cluster_neg_label;
	}elsif($use_coag_to_outgoing && $label1 eq 'cs_cluster_pos'){
		$label1 = $cs_cluster_pos_label;
	}

	$num='';
	# First check if we have this label in %num_from_label
	if(exists $num_from_label{"$label1"}){
		$num = $num_from_label{"$label1"};
	}else{
	# otherwise we can try to reorder the molecules in the label
		($comp1,$comp_ok)=&determine_cluster_composition($label1);
		if($comp_ok eq ''){
			$label_new=&create_label($comp1);
			if(exists $num_from_label{"$label_new"}){
				$num_from_label{"$label1"}=$num_from_label{"$label_new"};
				$num=$num_from_label{"$label1"};
			}
		}
	}
	
	return $num;
}


##############################################################################
## This subroutine finds the number of the corresponding dry cluster if this
## is a hydrate of a cluster in the system, the order of molecules is free
##############################################################################

# get_corresponding_dry: ($iclus,$nwaters) = get_corresponding_dry($label_in)
sub get_corresponding_dry(){
	my($iclus,$label_in,$imol,@temp_composition,$iwater,$nwaters,$temp_label);
	
	$label_in=$_[0];

	$nwaters=0;
	# Checking if we have the cluster in the system
	$iclus=&get_cluster_number($label_in);
	if($iclus eq '' && $lhydrate_average){
	# See if this is a hydrate of some cluster that we have
		@temp_composition=&find_composition($label_in);
		$iwater=-1;
		for($imol=0;$imol<=$#temp_composition;$imol++){
			if($temp_composition[$imol] =~ /^(\d+)$name_water$/){
				$iwater=$imol;
				$nwaters=$1;
			}
		}
		if($iwater>=0){
			# Remove the water and see if we have the dry cluster
			splice(@temp_composition,$iwater,1);
			$temp_label='';
			for($imol=0;$imol<=$#temp_composition;$imol++){
				$temp_label.=$temp_composition[$imol];
			}
			$iclus=&get_cluster_number($temp_label);
		}
	}
	
	return ($iclus,$nwaters)
}

##############################################################################
## This subroutine finds out if two clusters have the same composition,
## even if the molecules are in a different order in the name labels
##############################################################################

# compare_clusters: $lsame = compare_clusters($label1,$label2)

sub compare_clusters(){
	my($label1,$label2,$label_new,$comp1,$comp2,@composition1,@composition2,$lsame,$imol,$comp_ok);

	$label1=$_[0];
	if($use_coag_to_outgoing && $label1 eq 'cs_cluster'){
		$label1 = $cs_cluster_label;
	}elsif($use_coag_to_outgoing && $label1 eq 'cs_cluster_neg'){
		$label1 = $cs_cluster_neg_label;
	}elsif($use_coag_to_outgoing && $label1 eq 'cs_cluster_pos'){
		$label1 = $cs_cluster_pos_label;
	}
	$label2=$_[1];
	if($use_coag_to_outgoing && $label2 eq 'cs_cluster'){
		$label2 = $cs_cluster_label;
	}elsif($use_coag_to_outgoing && $label2 eq 'cs_cluster_neg'){
		$label2 = $cs_cluster_neg_label;
	}elsif($use_coag_to_outgoing && $label2 eq 'cs_cluster_pos'){
		$label2 = $cs_cluster_pos_label;
	}
	
	# First reordering the molecules in the labels if necessary
	if(!(exists $num_from_label{"$label1"})){
		($comp1,$comp_ok)=&determine_cluster_composition($label1);
		if($comp_ok eq ''){
			$label_new=&create_label($comp1);
			if(exists $num_from_label{"$label_new"}){
				$num_from_label{"$label1"}=$num_from_label{"$label_new"};
			}
		}
	}
	if(!(exists $num_from_label{"$label2"})){
		($comp2,$comp_ok)=&determine_cluster_composition($label2);
		if($comp_ok eq ''){
			$label_new=&create_label($comp2);
			if(exists $num_from_label{"$label_new"}){
				$num_from_label{"$label2"}=$num_from_label{"$label_new"};
			}
		}
	}
	
	# Now the labels point to the same cluster number if they have the same composition
	if((exists $num_from_label{"$label1"}) && (exists $num_from_label{"$label2"})){
		$lsame = ($num_from_label{"$label1"} ==  $num_from_label{"$label2"});
	}else{
		# This is just in case something funny happens - not sure if this is ever 
		@composition1=&find_composition($label1);
		@composition2=&find_composition($label2);
		$lsame=0;

		if($#composition1 == $#composition2){
			$lsame=1;
			for($imol=0;$imol<=$#composition1;$imol++){
				# see if all the elements from the 1st array belong to the 2nd
				$lsame=0 unless($composition1[$imol] ~~ @composition2);
			}
		}else{
			# these don't even have the same amount of molecule types
			$lsame=0; 
		}
			
	}
	return($lsame);
}

##############################################################################
## This subroutine finds out the composition of the cluster in the form e.g. 2A,1B,1D
## (i.e. both the amounts and names of the molecules)
##############################################################################

# find_composition: @composition = find_composition($ilabel)
sub find_composition(){
	my($ilabel,@composition,@nmols,@mol_name,$imol);

	$ilabel=$_[0];
	if($use_coag_to_outgoing && $ilabel eq 'cs_cluster'){
		$ilabel = $cs_cluster_label;
	}elsif($use_coag_to_outgoing && $ilabel eq 'cs_cluster_neg'){
		$ilabel = $cs_cluster_neg_label;
	}elsif($use_coag_to_outgoing && $ilabel eq 'cs_cluster_pos'){
		$ilabel = $cs_cluster_pos_label;
	}
	
	@nmols=split(/[a-zA-Z]+/,$ilabel);
	@mol_name=split(/-?\d+/,$ilabel);
	# do the shift because otherwise the first element will be empty
	shift(@mol_name);
	die "\nWhy doesn't the amount of molecule names match to the amount of molecule numbers in $label?\n\n" if ($#nmols != $#mol_name);
	for($imol=0;$imol<=$#nmols;$imol++){
		$composition[$imol]=$nmols[$imol] . $mol_name[$imol];
	}

	return(@composition);
}


###########################################################
## This subroutine checks to see if a given cluster is included
## in the clusters whose concentrations we are keeping track of;
## this returns 1 (true) if the cluster is valid, 0 (false) if it is not
###########################################################

# check_validity: $valid = check_validity($ilabel)
sub check_validity(){
	my ($ilabel,$iclus,$valid);

	$ilabel=$_[0];
	
	$valid=0;
	$iclus=&get_cluster_number($ilabel);
	if(($iclus ne '') && $iclus!=$n_flux_out && $iclus!=$n_flux_out_neg && $iclus!=$n_flux_out_pos){
		# if this is a valid cluster, it has a number
		# but if this is the cluster representing the coagulation sink, it's not really a valid cluster
		$valid=1;
	}

	return $valid;

}



####################################################################
## This subroutine takes in a label and sees if this is a monomer;
## 1 (true) is yes, 0 (false) is no
####################################################################

# check_monomer: $lmonomer = check_monomer($array_ref)
sub check_monomer(){
	my($total,$array_ref);

	$array_ref=$_[0];

	$total=&calculate_molecules($array_ref);

	if($total != 1){
		return 0;
	}else{
		return 1;
	}
}


####################################################################
## This subroutine takes in a label and calculates the total number
## of molecules in the cluster
####################################################################

# calculate_molecules: $total = calculate_molecules(\@temp_array)
sub calculate_molecules(){
	my(@temp_array,$total,$imol);

	@temp_array=@{ $_[0] };
	$total=0;
	for($imol=0;$imol<$nmol_types;$imol++){
		# Don't take the proton or the missing proton
		if($imol != $proton && $imol != $missing_proton){
			$total+=$temp_array[$imol];
		}
	}

	return $total;

}

####################################################################
## This calculates the mass of the cluster
####################################################################

# calculate_mass: $total_mass = calculate_mass(\@temp_array)
sub calculate_mass(){
	my(@temp_array,$total_mass,$imol);

	@temp_array=@{ $_[0] };
	$total_mass=0;
	for($imol=0;$imol<$nmol_types;$imol++){
		if($temp_array[$imol] != 0){
			$total_mass+=$temp_array[$imol]*$mass[$imol];
		}
	}

	return $total_mass;

}

####################################################################
## This calculates the radius from the total volume of the cluster
####################################################################

# calculate_radius: $radius = calculate_radius($array_ref)
sub calculate_radius(){
	my($total_volume,$radius,$array_ref);

	$array_ref=$_[0];

	($total_volume,$radius)=&calculate_volume_and_radius($array_ref);

	return $radius;

}

####################################################################
## This calculates the volume and radius of the cluster, assuming
## that it's just the sum of all the molecular volumes (which is
## assumed to be the mass divided by the density)
####################################################################

# calculate_volume_and_radius: ($total_volume, $radius) = calculate_volume_and_radius(\@temp_array)
sub calculate_volume_and_radius(){
	my(@temp_array,$total_volume,$volume,$imol);

	@temp_array=@{ $_[0] };
	$total_volume=0.0;
	for($imol=0;$imol<$nmol_types;$imol++){
		# Don't take the proton or the missing proton
		if($imol != $proton && $imol != $missing_proton){
			if($temp_array[$imol] != 0){
				$volume=$mass[$imol]/$density[$imol];
				$total_volume+=$temp_array[$imol]*$volume;
			}
		}
	}

	$radius=(3*$total_volume/(4*$pi))**(1.0/3.0);

	return ($total_volume, $radius);

}


####################################################################
## This subroutine takes the number of molecules in the cluster and
## creates a label for it
####################################################################

# create_label: $value = create_label(\@molecules_in_clust)
sub create_label(){
	my($value,$imol);
	my @molecules_in_clust=@{ $_[0] };

	# Create the label
	$value='';
	for($imol=0;$imol<$nmol_types;$imol++){
		if($molecules_in_clust[$imol] > 0){
			$value = $value . $molecules_in_clust[$imol] . $molecule_name[$imol];
		}
	}

	return $value;
}

####################################################################
## This subroutine takes in a label and figures out how many of each
## molecule type are present
####################################################################

# determine_cluster_composition: (\@molecules,$message) = determine_cluster_composition($ilabel)
sub determine_cluster_composition(){
	my($ilabel,@molecules,$imol,@nmols,@mol_name,$message);

	$ilabel=$_[0];
	if($use_coag_to_outgoing && $ilabel eq 'cs_cluster'){
		$ilabel = $cs_cluster_label;
	}elsif($use_coag_to_outgoing && $ilabel eq 'cs_cluster_neg'){
		$ilabel = $cs_cluster_neg_label;
	}elsif($use_coag_to_outgoing && $ilabel eq 'cs_cluster_pos'){
		$ilabel = $cs_cluster_pos_label;
	}
	
	# denote the charger ions as proton and removed proton, so they can easily be added and substracted from clusters
	if($ilabel eq $label_generic_neg){
		$ilabel = "1$label_missing_proton";
	}elsif($ilabel eq $label_generic_pos){
		$ilabel = "1$label_proton";
	}
	
	
	@nmols=split(/[a-zA-Z]+/,$ilabel);
	@mol_name=split(/-?\d+/,$ilabel);
	# shift the indices because otherwise the first element will be empty
	shift(@mol_name);
	# Going through the allowed molecule types to make a zero array
	for($imol=0;$imol<$nmol_types;$imol++){
		$molecules[$imol] = 0;
	}
	$message='';
	
	# Going through the molecule types in the cluster name, and if they are valid ones filling the array accordingly
	for($imol=0;$imol<=$#nmols;$imol++){
		if(exists $mol_num_from_name{$mol_name[$imol]}){
			$molecules[$mol_num_from_name{$mol_name[$imol]}]=$nmols[$imol];
		}else{
			$message="+ other molecule types";
		}
	}
	return (\@molecules,$message);
}


####################################################################
## This subroutine takes in a scalar and determines if it is a 
## positive number, possibly padded with spaces
####################################################################

# is_pos_number: $l_num = is_pos_number($a)
sub is_pos_number(){
	my($a,$l_num);
	
	$a=$_[0];
	$l_num = 0;
	
	if($a =~ m/^\s*\d+\.?\d*\s*$/){
		# 1 or 1. or 1.2
		$l_num = 1;
	}elsif($a =~ m/^\s*\.\d+\s*$/){
		# .1
		$l_num = 1;
	}elsif($a =~ m/^\s*\d+\.?\d*e[+-]?\d+\s*$/i){
		# 1e2, 1.e2, 1.2e3, 1.2e+3, 1.2e-3, 1.2E-3
		$l_num = 1;
	}elsif($a =~ m/^\s*\.\d+e[+-]?\d+\s*$/i){
		# .1e2, .1e+2, .1E-2
		$l_num = 1;
	}
	
	return $l_num;
}


####################################################################
####################################################################
## 
## List of subroutines
## 
####################################################################
####################################################################



# combine_labels: ($value,$valid_coll,$valid_evap,$valid) = combine_labels($cluster1,$cluster2)
# check_boundary: ($new_label,$lout,%nmonomers) = check_boundary($label0)

# get_cluster_number: $num = get_cluster_number($label1)
# get_corresponding_dry: ($iclus,$nwaters) = get_corresponding_dry($label_in)
# compare_clusters: $lsame = compare_clusters($label1,$label2)
# find_composition: @composition = find_composition($ilabel)

# check_validity: $valid = check_validity($ilabel)
# check_monomer: $lmonomer = check_monomer($array_ref)
# calculate_molecules: $total = calculate_molecules(\@temp_array)

# calculate_mass: $total_mass = calculate_mass(\@temp_array)
# calculate_radius: $radius = calculate_radius($array_ref)
# calculate_volume_and_radius: ($total_volume, $radius) = calculate_volume_and_radius(\@temp_array)

# create_label: $value = create_label(\@molecules_in_clust)
# determine_cluster_composition: (\@molecules,$message) = determine_cluster_composition($ilabel)

# is_pos_number: $l_num = is_pos_number($a)


